From ab656f86dd53d41bb191a05c085c254e7016d118 Mon Sep 17 00:00:00 2001 From: Luis Alvarez <luis@vercel.com> Date: Thu, 29 Jul 2021 22:02:10 -0500 Subject: [PATCH] Fixed eslint issues in multiple files --- components/cart/CartItem/CartItem.tsx | 3 + components/common/Footer/Footer.tsx | 2 +- components/common/Layout/Layout.tsx | 2 +- components/common/Searchbar/Searchbar.tsx | 51 ++++++------ .../product/ProductOptions/ProductOptions.tsx | 80 ++++++++++--------- .../product/ProductSidebar/ProductSidebar.tsx | 2 +- .../product/ProductSlider/ProductSlider.tsx | 14 ++-- .../ProductSliderControl.tsx | 45 +++++------ components/search.tsx | 2 +- components/ui/Modal/Modal.tsx | 10 ++- components/ui/Rating/Rating.tsx | 34 ++++---- components/ui/Sidebar/Sidebar.tsx | 11 +-- lib/search.tsx | 4 +- 13 files changed, 129 insertions(+), 131 deletions(-) diff --git a/components/cart/CartItem/CartItem.tsx b/components/cart/CartItem/CartItem.tsx index a59024e06..4453e0c08 100644 --- a/components/cart/CartItem/CartItem.tsx +++ b/components/cart/CartItem/CartItem.tsx @@ -70,6 +70,9 @@ const CartItem = ({ if (item.quantity !== Number(quantity)) { setQuantity(item.quantity) } + // TODO: currently not including quantity in deps is intended, but we should + // do this differently as it could break easily + // eslint-disable-next-line react-hooks/exhaustive-deps }, [item.quantity]) return ( diff --git a/components/common/Footer/Footer.tsx b/components/common/Footer/Footer.tsx index 04b80404e..8cfcc9666 100644 --- a/components/common/Footer/Footer.tsx +++ b/components/common/Footer/Footer.tsx @@ -73,7 +73,7 @@ const Footer: FC<Props> = ({ className, pages }) => { <div className="flex items-center text-primary text-sm"> <span className="text-primary">Created by</span> <a - rel="noopener" + rel="noopener noreferrer" href="https://vercel.com" aria-label="Vercel.com Link" target="_blank" diff --git a/components/common/Layout/Layout.tsx b/components/common/Layout/Layout.tsx index ff6d72aaf..2e53bed62 100644 --- a/components/common/Layout/Layout.tsx +++ b/components/common/Layout/Layout.tsx @@ -24,7 +24,7 @@ const Loading = () => ( ) const dynamicProps = { - loading: () => <Loading />, + loading: Loading, } const SignUpView = dynamic( diff --git a/components/common/Searchbar/Searchbar.tsx b/components/common/Searchbar/Searchbar.tsx index 0fc276d02..ee20a3ade 100644 --- a/components/common/Searchbar/Searchbar.tsx +++ b/components/common/Searchbar/Searchbar.tsx @@ -1,4 +1,4 @@ -import { FC, InputHTMLAttributes, useEffect, useMemo } from 'react' +import { FC, memo, useEffect } from 'react' import cn from 'classnames' import s from './Searchbar.module.css' import { useRouter } from 'next/router' @@ -13,7 +13,7 @@ const Searchbar: FC<Props> = ({ className, id = 'search' }) => { useEffect(() => { router.prefetch('/search') - }, []) + }, [router]) const handleKeyUp = (e: React.KeyboardEvent<HTMLInputElement>) => { e.preventDefault() @@ -32,32 +32,29 @@ const Searchbar: FC<Props> = ({ className, id = 'search' }) => { } } - return useMemo( - () => ( - <div className={cn(s.root, className)}> - <label className="hidden" htmlFor={id}> - Search - </label> - <input - id={id} - className={s.input} - placeholder="Search for products..." - defaultValue={router.query.q} - onKeyUp={handleKeyUp} - /> - <div className={s.iconContainer}> - <svg className={s.icon} fill="currentColor" viewBox="0 0 20 20"> - <path - fillRule="evenodd" - clipRule="evenodd" - d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" - /> - </svg> - </div> + return ( + <div className={cn(s.root, className)}> + <label className="hidden" htmlFor={id}> + Search + </label> + <input + id={id} + className={s.input} + placeholder="Search for products..." + defaultValue={router.query.q} + onKeyUp={handleKeyUp} + /> + <div className={s.iconContainer}> + <svg className={s.icon} fill="currentColor" viewBox="0 0 20 20"> + <path + fillRule="evenodd" + clipRule="evenodd" + d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z" + /> + </svg> </div> - ), - [] + </div> ) } -export default Searchbar +export default memo(Searchbar) diff --git a/components/product/ProductOptions/ProductOptions.tsx b/components/product/ProductOptions/ProductOptions.tsx index 9261406bc..456df4bfc 100644 --- a/components/product/ProductOptions/ProductOptions.tsx +++ b/components/product/ProductOptions/ProductOptions.tsx @@ -1,50 +1,52 @@ +import { memo } from 'react' import { Swatch } from '@components/product' import type { ProductOption } from '@commerce/types/product' import { SelectedOptions } from '../helpers' -import React from 'react' + interface ProductOptionsProps { options: ProductOption[] selectedOptions: SelectedOptions setSelectedOptions: React.Dispatch<React.SetStateAction<SelectedOptions>> } -const ProductOptions: React.FC<ProductOptionsProps> = React.memo( - ({ options, selectedOptions, setSelectedOptions }) => { - return ( - <div> - {options.map((opt) => ( - <div className="pb-4" key={opt.displayName}> - <h2 className="uppercase font-medium text-sm tracking-wide"> - {opt.displayName} - </h2> - <div className="flex flex-row py-4"> - {opt.values.map((v, i: number) => { - const active = selectedOptions[opt.displayName.toLowerCase()] - return ( - <Swatch - key={`${opt.id}-${i}`} - active={v.label.toLowerCase() === active} - variant={opt.displayName} - color={v.hexColors ? v.hexColors[0] : ''} - label={v.label} - onClick={() => { - setSelectedOptions((selectedOptions) => { - return { - ...selectedOptions, - [opt.displayName.toLowerCase()]: - v.label.toLowerCase(), - } - }) - }} - /> - ) - })} - </div> +const ProductOptions: React.FC<ProductOptionsProps> = ({ + options, + selectedOptions, + setSelectedOptions, +}) => { + return ( + <div> + {options.map((opt) => ( + <div className="pb-4" key={opt.displayName}> + <h2 className="uppercase font-medium text-sm tracking-wide"> + {opt.displayName} + </h2> + <div className="flex flex-row py-4"> + {opt.values.map((v, i: number) => { + const active = selectedOptions[opt.displayName.toLowerCase()] + return ( + <Swatch + key={`${opt.id}-${i}`} + active={v.label.toLowerCase() === active} + variant={opt.displayName} + color={v.hexColors ? v.hexColors[0] : ''} + label={v.label} + onClick={() => { + setSelectedOptions((selectedOptions) => { + return { + ...selectedOptions, + [opt.displayName.toLowerCase()]: v.label.toLowerCase(), + } + }) + }} + /> + ) + })} </div> - ))} - </div> - ) - } -) + </div> + ))} + </div> + ) +} -export default ProductOptions +export default memo(ProductOptions) diff --git a/components/product/ProductSidebar/ProductSidebar.tsx b/components/product/ProductSidebar/ProductSidebar.tsx index fe8a71aa5..fd1ef1e0a 100644 --- a/components/product/ProductSidebar/ProductSidebar.tsx +++ b/components/product/ProductSidebar/ProductSidebar.tsx @@ -23,7 +23,7 @@ const ProductSidebar: FC<ProductSidebarProps> = ({ product, className }) => { useEffect(() => { selectDefaultOptionFromProduct(product, setSelectedOptions) - }, []) + }, [product]) const variant = getProductVariant(product, selectedOptions) const addToCart = async () => { diff --git a/components/product/ProductSlider/ProductSlider.tsx b/components/product/ProductSlider/ProductSlider.tsx index 8c3441906..537a12a46 100644 --- a/components/product/ProductSlider/ProductSlider.tsx +++ b/components/product/ProductSlider/ProductSlider.tsx @@ -66,17 +66,13 @@ const ProductSlider: React.FC<ProductSliderProps> = ({ event.preventDefault() } - sliderContainerRef.current!.addEventListener( - 'touchstart', - preventNavigation - ) + const slider = sliderContainerRef.current! + + slider.addEventListener('touchstart', preventNavigation) return () => { - if (sliderContainerRef.current) { - sliderContainerRef.current!.removeEventListener( - 'touchstart', - preventNavigation - ) + if (slider) { + slider.removeEventListener('touchstart', preventNavigation) } } }, []) diff --git a/components/product/ProductSliderControl/ProductSliderControl.tsx b/components/product/ProductSliderControl/ProductSliderControl.tsx index 4e767b5db..5525c58de 100644 --- a/components/product/ProductSliderControl/ProductSliderControl.tsx +++ b/components/product/ProductSliderControl/ProductSliderControl.tsx @@ -1,31 +1,30 @@ +import { FC, MouseEventHandler, memo } from 'react' import cn from 'classnames' -import React from 'react' import s from './ProductSliderControl.module.css' import { ArrowLeft, ArrowRight } from '@components/icons' interface ProductSliderControl { - onPrev: React.MouseEventHandler<HTMLButtonElement> - onNext: React.MouseEventHandler<HTMLButtonElement> + onPrev: MouseEventHandler<HTMLButtonElement> + onNext: MouseEventHandler<HTMLButtonElement> } -const ProductSliderControl: React.FC<ProductSliderControl> = React.memo( - ({ onPrev, onNext }) => ( - <div className={s.control}> - <button - className={cn(s.leftControl)} - onClick={onPrev} - aria-label="Previous Product Image" - > - <ArrowLeft /> - </button> - <button - className={cn(s.rightControl)} - onClick={onNext} - aria-label="Next Product Image" - > - <ArrowRight /> - </button> - </div> - ) +const ProductSliderControl: FC<ProductSliderControl> = ({ onPrev, onNext }) => ( + <div className={s.control}> + <button + className={cn(s.leftControl)} + onClick={onPrev} + aria-label="Previous Product Image" + > + <ArrowLeft /> + </button> + <button + className={cn(s.rightControl)} + onClick={onNext} + aria-label="Next Product Image" + > + <ArrowRight /> + </button> + </div> ) -export default ProductSliderControl + +export default memo(ProductSliderControl) diff --git a/components/search.tsx b/components/search.tsx index 10fd5df68..e7663b5e5 100644 --- a/components/search.tsx +++ b/components/search.tsx @@ -7,7 +7,7 @@ import { useRouter } from 'next/router' import { Layout } from '@components/common' import { ProductCard } from '@components/product' import type { Product } from '@commerce/types/product' -import { Container, Grid, Skeleton } from '@components/ui' +import { Container, Skeleton } from '@components/ui' import useSearch from '@framework/product/use-search' diff --git a/components/ui/Modal/Modal.tsx b/components/ui/Modal/Modal.tsx index bb42b3d1b..de45c2814 100644 --- a/components/ui/Modal/Modal.tsx +++ b/components/ui/Modal/Modal.tsx @@ -27,13 +27,15 @@ const Modal: FC<ModalProps> = ({ children, onClose }) => { ) useEffect(() => { - if (ref.current) { - disableBodyScroll(ref.current, { reserveScrollBarGap: true }) + const modal = ref.current + + if (modal) { + disableBodyScroll(modal, { reserveScrollBarGap: true }) window.addEventListener('keydown', handleKey) } return () => { - if (ref && ref.current) { - enableBodyScroll(ref.current) + if (modal) { + enableBodyScroll(modal) } clearAllBodyScrollLocks() window.removeEventListener('keydown', handleKey) diff --git a/components/ui/Rating/Rating.tsx b/components/ui/Rating/Rating.tsx index 259e642ea..e3a9c6d12 100644 --- a/components/ui/Rating/Rating.tsx +++ b/components/ui/Rating/Rating.tsx @@ -1,4 +1,4 @@ -import React, { FC } from 'react' +import { FC, memo } from 'react' import rangeMap from '@lib/range-map' import { Star } from '@components/icons' import cn from 'classnames' @@ -7,21 +7,19 @@ export interface RatingProps { value: number } -const Quantity: React.FC<RatingProps> = React.memo(({ value = 5 }) => { - return ( - <div className="flex flex-row py-6 text-accent-9"> - {rangeMap(5, (i) => ( - <span - key={`star_${i}`} - className={cn('inline-block ml-1 ', { - 'text-accent-5': i >= Math.floor(value), - })} - > - <Star /> - </span> - ))} - </div> - ) -}) +const Quantity: FC<RatingProps> = ({ value = 5 }) => ( + <div className="flex flex-row py-6 text-accent-9"> + {rangeMap(5, (i) => ( + <span + key={`star_${i}`} + className={cn('inline-block ml-1 ', { + 'text-accent-5': i >= Math.floor(value), + })} + > + <Star /> + </span> + ))} + </div> +) -export default Quantity +export default memo(Quantity) diff --git a/components/ui/Sidebar/Sidebar.tsx b/components/ui/Sidebar/Sidebar.tsx index ce0eeefe2..700bb681a 100644 --- a/components/ui/Sidebar/Sidebar.tsx +++ b/components/ui/Sidebar/Sidebar.tsx @@ -16,13 +16,14 @@ const Sidebar: FC<SidebarProps> = ({ children, onClose }) => { const ref = useRef() as React.MutableRefObject<HTMLDivElement> useEffect(() => { - if (ref.current) { - disableBodyScroll(ref.current, { reserveScrollBarGap: true }) + const sidebar = ref.current + + if (sidebar) { + disableBodyScroll(sidebar, { reserveScrollBarGap: true }) } + return () => { - if (ref && ref.current) { - enableBodyScroll(ref.current) - } + if (sidebar) enableBodyScroll(sidebar) clearAllBodyScrollLocks() } }, []) diff --git a/lib/search.tsx b/lib/search.tsx index 87b42db36..eaeaf66fc 100644 --- a/lib/search.tsx +++ b/lib/search.tsx @@ -18,10 +18,10 @@ export function useSearchMeta(asPath: string) { c = parts[4] } - setPathname(path) + if (path !== pathname) setPathname(path) if (c !== category) setCategory(c) if (b !== brand) setBrand(b) - }, [asPath]) + }, [asPath, pathname, category, brand]) return { pathname, category, brand } }