/ packages / DApp / src / components / Filter.tsx
Filter.tsx
  1  import React, { useEffect, useState } from 'react'
  2  import styled from 'styled-components'
  3  import { Colors } from '../constants/styles'
  4  import filterIcon from '../assets/images/filter.svg'
  5  import arrowDownIcon from '../assets/images/arrowDown.svg'
  6  
  7  export type FilterListProps = {
  8    value: number
  9    setValue: (value: number) => void
 10    options: { value: number; text: string }[]
 11  }
 12  
 13  export const FilterList = ({ value, setValue, options }: FilterListProps) => {
 14    const [isOpened, setIsOpened] = useState(false)
 15  
 16    useEffect(() => {
 17      window.addEventListener('click', () => setIsOpened(false))
 18      return () => {
 19        window.removeEventListener('click', () => setIsOpened(false))
 20      }
 21    }, [])
 22  
 23    return (
 24      <Filter
 25        onClick={(e) => {
 26          e.stopPropagation()
 27          setIsOpened(!isOpened)
 28        }}
 29      >
 30        <Select>
 31          <SelectTrigger>{options.find((option) => option.value === value)?.text}</SelectTrigger>
 32          <SelectOptions className={isOpened ? 'opened' : undefined}>
 33            {options.map((option, key) => (
 34              <SelectOption
 35                className={option.value === value ? 'selected' : ''}
 36                key={key}
 37                onClick={() => setValue(option.value)}
 38              >
 39                {option.text}
 40              </SelectOption>
 41            ))}
 42          </SelectOptions>
 43        </Select>
 44      </Filter>
 45    )
 46  }
 47  
 48  const Filter = styled.button`
 49    display: flex;
 50    align-items: center;
 51    height: 36px;
 52    position: relative;
 53    padding-left: 5px;
 54    padding-right: 1px;
 55    font-weight: 500;
 56    font-size: 15px;
 57    line-height: 22px;
 58    color: ${Colors.VioletDark};
 59    border: 1px solid #e6ecf0;
 60    border-radius: 14px;
 61    appearance: none;
 62    outline: none;
 63  
 64    &:focus,
 65    &:active {
 66      border: 1px solid ${Colors.Violet};
 67    }
 68  `
 69  
 70  const Select = styled.div`
 71    position: relative;
 72    display: flex;
 73    flex-direction: column;
 74  `
 75  const SelectTrigger = styled.div`
 76    position: relative;
 77    min-width: 167px;
 78    padding: 0 28px;
 79    box-sizing: border-box;
 80  
 81    @media (max-width: 600px) {
 82      font-size: 0;
 83      min-width: unset;
 84    }
 85  
 86    &::before {
 87      content: '';
 88      width: 24px;
 89      height: 24px;
 90      position: absolute;
 91      top: 50%;
 92      left: 0;
 93      transform: translateY(-50%);
 94      background-image: url(${filterIcon});
 95    }
 96  
 97    &::after {
 98      content: '';
 99      width: 24px;
100      height: 24px;
101      position: absolute;
102      top: 50%;
103      right: 0;
104      transform: translateY(-50%);
105      background-image: url(${arrowDownIcon});
106    }
107  `
108  const SelectOptions = styled.div`
109    position: absolute;
110    display: block;
111    width: 175px;
112    top: calc(100% + 11px);
113    right: 0;
114    opacity: 0;
115    visibility: hidden;
116    pointer-events: none;
117    transition: all 0.3s;
118    border: 1px solid ${Colors.GrayBorder};
119    border-radius: 16px 4px 16px 16px;
120  
121    &.opened {
122      opacity: 1;
123      background: ${Colors.White};
124      visibility: visible;
125      pointer-events: all;
126      z-index: 10;
127    }
128  `
129  const SelectOption = styled.span`
130    position: relative;
131    display: block;
132    width: 100%;
133    font-weight: 500;
134    font-size: 15px;
135    line-height: 22px;
136    text-align: center;
137    padding: 11px 0;
138    cursor: pointer;
139    transition: all 0.3s;
140  
141    &:first-child {
142      border-radius: 16px 4px 0 0;
143    }
144  
145    &:last-child {
146      border-radius: 0 0 16px 16px;
147    }
148  
149    &:not(:last-child) {
150      border-bottom: 1px solid ${Colors.GrayBorder};
151    }
152  
153    &:hover {
154      background: ${Colors.Violet};
155      color: ${Colors.White};
156    }
157  
158    &.selected {
159      @media (max-width: 600px) {
160        background: ${Colors.Violet};
161        color: ${Colors.White};
162      }
163    }
164  `