|
| 1 | +// Copyright 2019-2024 @polkadot/extension-polkagate authors & contributors |
| 2 | +// SPDX-License-Identifier: Apache-2.0 |
| 3 | + |
| 4 | +/* eslint-disable react/jsx-max-props-per-line */ |
| 5 | + |
| 6 | +import type { FilterAction, FilterState, SortAction, SortState } from '../utils/types'; |
| 7 | + |
| 8 | +import { FilterAltOutlined as FilterIcon, FilterList as FilterListIcon, ImportExport as ImportExportIcon } from '@mui/icons-material'; |
| 9 | +import { Divider, FormControl, FormControlLabel, Grid, Popover, Radio, RadioGroup, Typography, useTheme } from '@mui/material'; |
| 10 | +import React, { useCallback } from 'react'; |
| 11 | + |
| 12 | +import Checkbox2 from '../../../components/Checkbox2'; |
| 13 | +import { useTranslation } from '../../../hooks'; |
| 14 | + |
| 15 | +interface Props { |
| 16 | + dispatchFilter: React.Dispatch<FilterAction>; |
| 17 | + filters: FilterState; |
| 18 | + dispatchSort: React.Dispatch<SortAction>; |
| 19 | + sort: SortState; |
| 20 | +} |
| 21 | + |
| 22 | +const Filters = React.memo(function Filters ({ dispatchFilter, dispatchSort, filters, sort }: Props) { |
| 23 | + const { t } = useTranslation(); |
| 24 | + const theme = useTheme(); |
| 25 | + |
| 26 | + const onFilters = useCallback((filter: keyof FilterState) => () => { |
| 27 | + dispatchFilter({ filter }); |
| 28 | + }, [dispatchFilter]); |
| 29 | + |
| 30 | + const onSort = useCallback((enable: keyof SortState, unable: keyof SortState) => () => { |
| 31 | + dispatchSort({ enable, unable }); |
| 32 | + }, [dispatchSort]); |
| 33 | + |
| 34 | + return ( |
| 35 | + <Grid alignItems='flex-start' container display='block' item sx={{ borderRadius: '10px', maxWidth: '300px', p: '10px 20px', width: 'max-content' }}> |
| 36 | + <Grid alignItems='center' container item> |
| 37 | + <FilterListIcon sx={{ color: 'secondary.light', height: '25px', mr: '10px', width: '25px' }} /> |
| 38 | + <Typography fontSize='16px' fontWeight={400}> |
| 39 | + {t('Filters')} |
| 40 | + </Typography> |
| 41 | + <Divider sx={{ bgcolor: 'divider', height: '2px', mt: '5px', width: '100%' }} /> |
| 42 | + <Checkbox2 |
| 43 | + checked={filters.collections} |
| 44 | + iconStyle={{ marginRight: '6px', width: '20px' }} |
| 45 | + label={t('Collections')} |
| 46 | + labelStyle={{ fontSize: '16px', fontWeight: 400 }} |
| 47 | + onChange={onFilters('collections')} |
| 48 | + style={{ mt: '15px', width: '100%' }} |
| 49 | + /> |
| 50 | + <Checkbox2 |
| 51 | + checked={filters.nft} |
| 52 | + iconStyle={{ marginRight: '6px', width: '20px' }} |
| 53 | + label={t('NFTs')} |
| 54 | + labelStyle={{ fontSize: '16px', fontWeight: 400 }} |
| 55 | + onChange={onFilters('nft')} |
| 56 | + style={{ mt: '15px', width: '100%' }} |
| 57 | + /> |
| 58 | + <Checkbox2 |
| 59 | + checked={filters.unique} |
| 60 | + iconStyle={{ marginRight: '6px', width: '20px' }} |
| 61 | + label={t('Uniques')} |
| 62 | + labelStyle={{ fontSize: '16px', fontWeight: 400 }} |
| 63 | + onChange={onFilters('unique')} |
| 64 | + style={{ mt: '15px', width: '100%' }} |
| 65 | + /> |
| 66 | + <Checkbox2 |
| 67 | + checked={filters.kusama} |
| 68 | + iconStyle={{ marginRight: '6px', width: '20px' }} |
| 69 | + label={t('Kusama Asset Hub')} |
| 70 | + labelStyle={{ fontSize: '16px', fontWeight: 400 }} |
| 71 | + onChange={onFilters('kusama')} |
| 72 | + style={{ mt: '15px', width: '100%' }} |
| 73 | + /> |
| 74 | + <Checkbox2 |
| 75 | + checked={filters.polkadot} |
| 76 | + iconStyle={{ marginRight: '6px', width: '20px' }} |
| 77 | + label={t('Polkadot Asset Hub')} |
| 78 | + labelStyle={{ fontSize: '16px', fontWeight: 400 }} |
| 79 | + onChange={onFilters('polkadot')} |
| 80 | + style={{ mt: '15px', width: '100%' }} |
| 81 | + /> |
| 82 | + </Grid> |
| 83 | + <Grid alignItems='center' container item mt='15px'> |
| 84 | + <ImportExportIcon sx={{ color: 'secondary.light', height: '30px', mr: '10px', width: '30px' }} /> |
| 85 | + <Typography fontSize='16px' fontWeight={400}> |
| 86 | + {t('Sort')} |
| 87 | + </Typography> |
| 88 | + <Divider sx={{ bgcolor: 'divider', height: '2px', mt: '5px', width: '100%' }} /> |
| 89 | + <FormControl fullWidth> |
| 90 | + <RadioGroup |
| 91 | + aria-labelledby='sort-price' |
| 92 | + name='sort-price' |
| 93 | + > |
| 94 | + <FormControlLabel checked={sort.highPrice} control={<Radio style={{ color: theme.palette.secondary.main }} />} label={t('Price: High to Low')} onClick={onSort('highPrice', 'lowPrice')} slotProps={{ typography: { fontWeight: 400 } }} value='highPrice' /> |
| 95 | + <FormControlLabel checked={sort.lowPrice} control={<Radio style={{ color: theme.palette.secondary.main }} />} label={t('Price: Low to High')} onClick={onSort('lowPrice', 'highPrice')} slotProps={{ typography: { fontWeight: 400 } }} value='lowPrice' /> |
| 96 | + </RadioGroup> |
| 97 | + </FormControl> |
| 98 | + </Grid> |
| 99 | + </Grid> |
| 100 | + ); |
| 101 | +}); |
| 102 | + |
| 103 | +function NftFilters ({ dispatchFilter, dispatchSort, filters, sort }: Props): React.ReactElement { |
| 104 | + const theme = useTheme(); |
| 105 | + |
| 106 | + const [anchorEl, setAnchorEl] = React.useState<HTMLButtonElement | null>(null); |
| 107 | + |
| 108 | + const handleClose = useCallback(() => { |
| 109 | + setAnchorEl(null); |
| 110 | + }, []); |
| 111 | + |
| 112 | + const handleClick = useCallback((event: React.MouseEvent<HTMLButtonElement>) => { |
| 113 | + setAnchorEl(event.currentTarget); |
| 114 | + }, []); |
| 115 | + |
| 116 | + const open = Boolean(anchorEl); |
| 117 | + const id = open ? 'simple-popover' : undefined; |
| 118 | + |
| 119 | + return ( |
| 120 | + <> |
| 121 | + <Grid aria-describedby={id} component='button' container item onClick={handleClick} sx={{ bgcolor: 'transparent', border: 'none', height: 'fit-content', p: 0, width: 'fit-content' }}> |
| 122 | + <FilterIcon sx={{ color: 'secondary.light', cursor: 'pointer', height: '30px', width: '30px' }} /> |
| 123 | + </Grid> |
| 124 | + <Popover |
| 125 | + PaperProps={{ |
| 126 | + sx: { backgroundImage: 'none', bgcolor: 'background.paper', border: '1px solid', borderColor: theme.palette.mode === 'dark' ? 'secondary.main' : 'transparent', borderRadius: '7px', boxShadow: theme.palette.mode === 'dark' ? '0px 4px 4px rgba(255, 255, 255, 0.25)' : '0px 0px 25px 0px rgba(0, 0, 0, 0.50)' } |
| 127 | + }} |
| 128 | + anchorEl={anchorEl} |
| 129 | + anchorOrigin={{ |
| 130 | + horizontal: 'right', |
| 131 | + vertical: 'bottom' |
| 132 | + }} |
| 133 | + id={id} |
| 134 | + onClose={handleClose} |
| 135 | + open={open} |
| 136 | + sx={{ mt: '5px' }} |
| 137 | + transformOrigin={{ |
| 138 | + horizontal: 'right', |
| 139 | + vertical: 'top' |
| 140 | + }} |
| 141 | + > |
| 142 | + <Filters |
| 143 | + dispatchFilter={dispatchFilter} |
| 144 | + dispatchSort={dispatchSort} |
| 145 | + filters={filters} |
| 146 | + sort={sort} |
| 147 | + /> |
| 148 | + </Popover> |
| 149 | + </> |
| 150 | + ); |
| 151 | +} |
| 152 | + |
| 153 | +export default React.memo(NftFilters); |
0 commit comments