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 }
 }