From 04d79f1f7f4542e984f84f943d7d99b3a57605f5 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Wed, 14 Oct 2020 17:21:29 -0300 Subject: [PATCH] Loading State for Button --- .../product/ProductView/ProductView.tsx | 40 ++++++++++++++----- components/ui/Button/Button.module.css | 6 +-- components/ui/Button/Button.tsx | 11 ++++- .../ui/LoadingDots/LoadingDots.module.css | 32 +++++++++++++++ components/ui/LoadingDots/LoadingDots.tsx | 13 ++++++ components/ui/LoadingDots/index.ts | 1 + components/ui/Logo/index.ts | 1 - components/ui/index.ts | 13 +++--- tailwind.config.js | 7 +++- 9 files changed, 100 insertions(+), 24 deletions(-) create mode 100644 components/ui/LoadingDots/LoadingDots.module.css create mode 100644 components/ui/LoadingDots/LoadingDots.tsx create mode 100644 components/ui/LoadingDots/index.ts delete mode 100644 components/ui/Logo/index.ts diff --git a/components/product/ProductView/ProductView.tsx b/components/product/ProductView/ProductView.tsx index 2eb132355..2348258df 100644 --- a/components/product/ProductView/ProductView.tsx +++ b/components/product/ProductView/ProductView.tsx @@ -4,7 +4,7 @@ import { FC, useState } from 'react' import s from './ProductView.module.css' import { Colors } from '@components/ui/types' import { useUI } from '@components/ui/context' -import { Button, Container } from '@components/ui' +import { Button, Container, LoadingDots } from '@components/ui' import { Swatch, ProductSlider } from '@components/product' import useAddItem from '@lib/bigcommerce/cart/use-add-item' import type { Product } from '@lib/bigcommerce/api/operations/get-product' @@ -25,18 +25,28 @@ const SIZES = ['s', 'm', 'l', 'xl', 'xxl'] const ProductView: FC = ({ product, className }) => { const addItem = useAddItem() const { openSidebar } = useUI() + const [choices, setChoices] = useState({ size: null, color: null, }) + const [loading, setLoading] = useState(false) + const addToCart = async () => { - // TODO: loading state by awating the promise - await addItem({ - productId: product.entityId, - variantId: product.variants.edges?.[0]?.node.entityId!, - }) - openSidebar() + setLoading(true) + + try { + await addItem({ + productId: product.entityId, + variantId: product.variants.edges?.[0]?.node.entityId!, + }) + openSidebar() + setLoading(false) + } catch (err) { + // Error err. + setLoading(false) + } } const activeSize = choices.size @@ -75,11 +85,16 @@ const ProductView: FC = ({ product, className }) => {
- {product.images.edges?.map((image) => ( - + {product.images.edges?.map((image, i) => ( + ))}
+
@@ -128,7 +143,12 @@ const ProductView: FC = ({ product, className }) => { />
-
diff --git a/components/ui/Button/Button.module.css b/components/ui/Button/Button.module.css index f60c71039..8e59fea27 100644 --- a/components/ui/Button/Button.module.css +++ b/components/ui/Button/Button.module.css @@ -2,7 +2,7 @@ @apply text-secondary 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 focus:outline-none - border border-transparent; + border border-transparent items-center; } .root:hover { @@ -17,6 +17,6 @@ @apply bg-gray-600; } -s.filled { - @apply text-white bg-black; +.loading { + @apply bg-accent-1 text-accent-3 border-accent-2 cursor-not-allowed; } diff --git a/components/ui/Button/Button.tsx b/components/ui/Button/Button.tsx index c5046a3fd..c453aaf1d 100644 --- a/components/ui/Button/Button.tsx +++ b/components/ui/Button/Button.tsx @@ -8,7 +8,7 @@ import React, { import mergeRefs from 'react-merge-refs' import { useButton } from 'react-aria' import s from './Button.module.css' - +import { LoadingDots } from '@components/ui' export interface ButtonProps extends ButtonHTMLAttributes { href?: string className?: string @@ -17,6 +17,7 @@ export interface ButtonProps extends ButtonHTMLAttributes { type?: 'submit' | 'reset' | 'button' Component?: string | JSXElementConstructor width?: string | number + loading?: boolean } const Button: React.FC = forwardRef((props, buttonRef) => { @@ -30,6 +31,7 @@ const Button: React.FC = forwardRef((props, buttonRef) => { disabled, width, Component = 'button', + loading = false, ...rest } = props const ref = useRef(null) @@ -47,7 +49,7 @@ const Button: React.FC = forwardRef((props, buttonRef) => { const rootClassName = cn( s.root, { - [s.filled]: variant === 'filled', + [s.loading]: loading, }, className ) @@ -66,6 +68,11 @@ const Button: React.FC = forwardRef((props, buttonRef) => { data-active={isPressed ? '' : undefined} > {children} + {loading && ( + + + + )} ) }) diff --git a/components/ui/LoadingDots/LoadingDots.module.css b/components/ui/LoadingDots/LoadingDots.module.css new file mode 100644 index 000000000..0a8fe5bf0 --- /dev/null +++ b/components/ui/LoadingDots/LoadingDots.module.css @@ -0,0 +1,32 @@ +@keyframes blink { + 0% { + opacity: 0.2; + } + 20% { + opacity: 1; + } + 100% { + opacity: 0.2; + } +} + +.loading { + @apply inline-flex text-center items-center leading-7; + + & span { + @apply bg-accent-6 rounded-full h-2 w-2; + animation-name: blink; + animation-duration: 1.4s; + animation-iteration-count: infinite; + animation-fill-mode: both; + margin: 0 2px; + + &:nth-of-type(2) { + animation-delay: 0.2s; + } + + &:nth-of-type(3) { + animation-delay: 0.4s; + } + } +} diff --git a/components/ui/LoadingDots/LoadingDots.tsx b/components/ui/LoadingDots/LoadingDots.tsx new file mode 100644 index 000000000..eb26c7340 --- /dev/null +++ b/components/ui/LoadingDots/LoadingDots.tsx @@ -0,0 +1,13 @@ +import s from './LoadingDots.module.css' + +const LoadingDots: React.FC = () => { + return ( + + + + + + ) +} + +export default LoadingDots diff --git a/components/ui/LoadingDots/index.ts b/components/ui/LoadingDots/index.ts new file mode 100644 index 000000000..63df282bf --- /dev/null +++ b/components/ui/LoadingDots/index.ts @@ -0,0 +1 @@ +export { default } from './LoadingDots' diff --git a/components/ui/Logo/index.ts b/components/ui/Logo/index.ts deleted file mode 100644 index 93dce23b4..000000000 --- a/components/ui/Logo/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './Logo' diff --git a/components/ui/index.ts b/components/ui/index.ts index a5a097c62..db12144e4 100644 --- a/components/ui/index.ts +++ b/components/ui/index.ts @@ -1,7 +1,8 @@ -export { default as Button } from './Button' -export { default as Container } from './Container' -export { default as Sidebar } from './Sidebar' -export { default as Logo } from './Logo' -export { default as Grid } from './Grid' -export { default as Marquee } from './Marquee' export { default as Hero } from './Hero' +export { default as Logo } from './LoadingDots' +export { default as Grid } from './Grid' +export { default as Button } from './Button' +export { default as Sidebar } from './Sidebar' +export { default as Marquee } from './Marquee' +export { default as Container } from './Container' +export { default as LoadingDots } from './LoadingDots' diff --git a/tailwind.config.js b/tailwind.config.js index 8cbc245b8..8a4316ecd 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -15,9 +15,12 @@ module.exports = { }, colors: { 'accent-1': '#FAFAFA', - 'accent-2': '#F1F3F5', + 'accent-2': '#eaeaea', + 'accent-3': '#999999', 'accent-4': '#888', - 'accent-6': '#E5E5E5', + 'accent-5': '#666666', + 'accent-6': '#444444', + 'accent-7': '#333333', 'accent-8': '#111111', violet: '#7928CA', pink: '#FF0080',