synapsecns/sanguine

View on GitHub
packages/synapse-interface/components/ui/ChainSelector.tsx

Summary

Maintainability
A
0 mins
Test Coverage
import React, { useEffect, useState } from 'react'
import { useDispatch } from 'react-redux'
import { useTranslations } from 'next-intl'

import { type Chain } from '@/utils/types'
import { SelectSpecificNetworkButton } from '@/components/ui/SelectSpecificNetworkButton'
import { segmentAnalyticsEvent } from '@/contexts/SegmentAnalyticsProvider'
import { SelectorWrapper } from '@/components/ui/SelectorWrapper'
import { ListSectionWrapper } from '@/components/ui/ListSectionWrapper'
import { ChainSelectorTypes } from '@/components/ui/types'
import { useKeyPress } from '@/utils/hooks/useKeyPress'

export function ChainSelector({
  dataTestId,
  isOrigin,
  selectedItem,
  label,
  placeholder,
  itemListFunction,
  setFunction,
  action,
  disabled,
}: ChainSelectorTypes) {
  const [searchStr, setSearchStr] = useState('')
  const [open, setOpen] = useState(false)

  const [currentId, setCurrentId] = useState(null)
  const dispatch = useDispatch()

  const t = useTranslations('Bridge')

  const handleSetChainId = (chainId) => {
    if (selectedItem?.id !== chainId) {
      const eventTitle = `[${action} User Action] Sets new ${
        isOrigin ? 'from' : 'to'
      }ChainId`

      const eventData = isOrigin
        ? {
            previousFromChainId: selectedItem?.id,
            newFromChainId: chainId,
          }
        : {
            previousToChainId: selectedItem?.id,
            newToChainId: chainId,
          }

      segmentAnalyticsEvent(eventTitle, eventData, true)
      dispatch(setFunction(chainId))
    }
  }

  const itemList = itemListFunction(searchStr)
  const flatItemList = Object.entries(itemList).reduce(
    (acc, [_, value]) => [...acc, ...(value as Chain[])],
    []
  )

  const onClose = () => {
    setSearchStr('')
    setCurrentId(null)
    setOpen(false)
  }

  const onSearch = (str: string) => {
    setSearchStr(str)
    setCurrentId(null)
  }

  const arrowUp = useKeyPress('ArrowUp', open)
  const arrowDown = useKeyPress('ArrowDown', open)
  const enterPress = useKeyPress('Enter', open)

  const arrowDownFunc = () => {
    const currentIndex = flatItemList.findIndex((item) => item.id === currentId)
    const nextIndex = currentIndex + 1
    if (arrowDown && nextIndex < flatItemList.length) {
      setCurrentId(flatItemList[nextIndex].id)
    }
  }

  const arrowUpFunc = () => {
    const currentIndex = flatItemList.findIndex((item) => item.id === currentId)
    const prevIndex = currentIndex - 1
    if (arrowUp && prevIndex >= 0) {
      setCurrentId(flatItemList[prevIndex].id)
    }
  }

  useEffect(arrowDownFunc, [arrowDown])
  useEffect(arrowUpFunc, [arrowUp])

  useEffect(() => {
    if (currentId !== null) {
      handleSetChainId(currentId)
      onClose()
    }
  }, [enterPress])

  return (
    <SelectorWrapper
      key={dataTestId}
      dataTestId={dataTestId}
      label={label}
      placeholder={placeholder ?? t('Network')}
      selectedItem={selectedItem}
      searchStr={searchStr}
      onSearch={onSearch}
      open={open}
      setOpen={setOpen}
      onClose={onClose}
      disabled={disabled}
    >
      {Object.entries(itemList).map(([key, value]: [string, Chain[]]) => {
        return value.length ? (
          <ListSectionWrapper sectionKey={key} key={key}>
            {value.map((chain) => (
              <SelectSpecificNetworkButton
                dataId={dataTestId}
                key={chain.id}
                itemChainId={chain.id}
                isOrigin={isOrigin}
                isSelected={selectedItem?.id === chain.id}
                isActive={chain.id === currentId}
                onClick={() => handleSetChainId(chain.id)}
              />
            ))}
          </ListSectionWrapper>
        ) : null
      })}
    </SelectorWrapper>
  )
}