synapsecns/sanguine

View on GitHub
packages/synapse-interface/components/Portfolio/components/SearchBar.tsx

Summary

Maintainability
A
2 hrs
Test Coverage
import React, { useEffect } from 'react'
import { Address } from 'viem'
import { useTranslations } from 'next-intl'

import { useAppDispatch } from '@/store/hooks'
import {
  usePortfolioActionHandlers,
  usePortfolioState,
  fetchAndStoreSearchInputPortfolioBalances,
} from '@/slices/portfolio/hooks'
import { PortfolioTabs } from '@/slices/portfolio/actions'
import { PortfolioState } from '@/slices/portfolio/reducer'
import { getValidAddress } from '@/utils/isValidAddress'
import { isTransactionHash } from '@/utils/validators'
import { getTransactionHashExplorerLink } from '../../Activity/Transaction/components/TransactionExplorerLink'
import { ClearSearchButton } from './ClearSearchButton'
import { useIsFocused } from '@/utils/hooks/useIsFocused'
import { useIsMounted } from '@/utils/hooks/useIsMounted'
import { useSearchInputState } from '../hooks/useSearchInputStatus'

export const inputRef = React.createRef<HTMLInputElement>()

export const SearchBar = () => {
  const dispatch = useAppDispatch()
  const { onSearchInput, clearSearchInput } = usePortfolioActionHandlers()
  const { activeTab, searchInput, searchedBalances }: PortfolioState =
    usePortfolioState()
  const { isSearchInputActive, isMasqueradeActive } = useSearchInputState()

  const isMounted = useIsMounted()
  const isFocused = useIsFocused(inputRef)

  const placeholder = getFilterPlaceholder(activeTab)

  const checksumValidAddress = getValidAddress(searchInput)
  const isSearchInputTransactionHash = isTransactionHash(searchInput)

  useEffect(() => {
    if (checksumValidAddress) {
      isMasqueradeActive
        ? clearSearchInput()
        : dispatch(
            fetchAndStoreSearchInputPortfolioBalances(
              checksumValidAddress as Address
            )
          )
    }
  }, [checksumValidAddress, searchedBalances])

  /** Trigger opening new browser window for tx on block explorer */
  useEffect(() => {
    if (isSearchInputTransactionHash) {
      const explorerLink: string = getTransactionHashExplorerLink({
        transactionHash: searchInput,
      })
      window.open(explorerLink, '_blank', 'noopener,noreferrer')
    }
  }, [isSearchInputTransactionHash])

  return (
    <div
      id="portfolio-search-bar"
      className={`
        relative flex items-center ml-auto
        border rounded-xl
        ${!isMounted && 'border-opacity-30'}
        ${
          isFocused || isSearchInputActive
            ? 'border-fuchsia-400 bg-tint'
            : 'border-separator bg-transparent'
        }
      `}
    >
      <FilterInput
        placeholder={placeholder}
        searchStr={searchInput}
        onSearch={onSearchInput}
        disabled={isMounted ? false : true}
      />
      <ClearSearchButton
        show={isSearchInputActive}
        onClick={clearSearchInput}
      />
    </div>
  )
}

const FilterInput = ({
  searchStr,
  onSearch,
  placeholder,
  disabled = false,
}: {
  searchStr: string
  onSearch: (str: string) => void
  placeholder: string
  disabled: boolean
}) => {
  return (
    <input
      id="filter-input"
      ref={inputRef}
      placeholder={placeholder}
      onChange={(e) => onSearch(e.target.value)}
      value={searchStr}
      disabled={disabled}
      tabIndex={0}
      className={`
        flex-grow py-2.5 pl-4 pr-1
        font-normal text-sm text-primaryTextColor
        border h-full w-6/12 rounded-xl bg-transparent custom-shadow
        placeholder-white placeholder-opacity-40
        border-transparent outline-none ring-0
        focus:outline-none focus:ring-0 focus:border-transparent
        ${disabled && 'opacity-30'}
      `}
    />
  )
}

function getFilterPlaceholder(activeTab: PortfolioTabs | undefined) {
  const t = useTranslations('Portfolio')

  switch (activeTab) {
    case PortfolioTabs.PORTFOLIO:
      return `${t('Tokens, chains')}...`
    case PortfolioTabs.ACTIVITY:
      return `${t('Bridge txs')}...`
    default:
      return `${t('Search')}...`
  }
}