1+ import { Drawer , styled , useMediaQuery } from '@mui/material' ;
12import { SelectChangeEvent } from '@mui/material/Select' ;
23import React from 'react' ;
34import { Button } from '../base/Button' ;
@@ -8,6 +9,7 @@ import { Paper } from '../base/Paper';
89import { Select } from '../base/Select' ;
910import { FilterIcon } from '../icons' ;
1011import { useTheme } from '../theme' ;
12+ import { darkModalGradient , lightModalGradient } from '../theme/colors/colors' ;
1113import PopperListener from './PopperListener' ;
1214import { TooltipIcon } from './TooltipIconButton' ;
1315
@@ -26,6 +28,16 @@ export interface UniversalFilterProps {
2628 id : string ;
2729}
2830
31+ export const FilterHeader = styled ( 'div' ) ( ( { theme } ) => ( {
32+ background : theme . palette . mode === 'light' ? lightModalGradient . fotter : darkModalGradient . fotter ,
33+ padding : '0.75rem 1rem' ,
34+ margin : '-1rem -1rem 1rem -1rem' ,
35+ display : 'flex' ,
36+ justifyContent : 'space-between' ,
37+ alignItems : 'center' ,
38+ color : theme . palette . text . primary
39+ } ) ) ;
40+
2941function UniversalFilter ( {
3042 filters,
3143 selectedFilters,
@@ -37,11 +49,22 @@ function UniversalFilter({
3749} : UniversalFilterProps ) : JSX . Element {
3850 const [ anchorEl , setAnchorEl ] = React . useState < null | HTMLElement > ( null ) ;
3951 const [ open , setOpen ] = React . useState ( false ) ;
52+
4053 const theme = useTheme ( ) ;
54+ const isMobile = useMediaQuery ( theme . breakpoints . down ( 'sm' ) ) ;
55+
56+ const handleClick = ( event : React . MouseEvent < HTMLElement > ) => {
57+ setAnchorEl ( event . currentTarget ) ;
58+ setOpen ( ( prevOpen ) => ! prevOpen ) ;
59+ } ;
60+
61+ const handleClose = ( ) => {
62+ setAnchorEl ( null ) ;
63+ setOpen ( false ) ;
64+ } ;
4165
4266 const handleFilterChange = ( event : React . ChangeEvent < { value : string } > , columnName : string ) => {
4367 const value = event . target . value ;
44-
4568 setSelectedFilters ( ( prevFilters ) => ( {
4669 ...prevFilters ,
4770 [ columnName ] : value
@@ -53,98 +76,96 @@ function UniversalFilter({
5376 handleApplyFilter ( ) ;
5477 } ;
5578
56- const handleClick = ( event : React . MouseEvent < HTMLElement > ) => {
57- setAnchorEl ( event . currentTarget ) ;
58- setOpen ( ( previousOpen ) => ! previousOpen ) ;
59- } ;
60-
61- const canBeOpen = open && Boolean ( anchorEl ) ;
62- const idx = canBeOpen ? 'transition-popper' : undefined ;
79+ const renderFilterContent = ( ) => (
80+ < div >
81+ < FilterHeader >
82+ < h3 > Filters: </ h3 >
83+ </ FilterHeader >
84+ { Object . keys ( filters ) . map ( ( filterColumn ) => {
85+ const options = filters [ filterColumn ] . options ;
86+ return (
87+ < div key = { filterColumn } role = "presentation" >
88+ < InputLabel id = { filters [ filterColumn ] . name } > { filters [ filterColumn ] . name } </ InputLabel >
89+ < Select
90+ defaultValue = "All"
91+ key = { filterColumn }
92+ value = { selectedFilters [ filterColumn ] }
93+ variant = { variant }
94+ onChange = { ( e : SelectChangeEvent < unknown > ) =>
95+ handleFilterChange ( e as React . ChangeEvent < { value : string } > , filterColumn )
96+ }
97+ style = { {
98+ width : '20rem' ,
99+ marginBottom : '1rem'
100+ } }
101+ inputProps = { { 'aria-label' : 'Without label' } }
102+ displayEmpty
103+ >
104+ { showAllOption && < MenuItem value = "All" > All</ MenuItem > }
105+ { options . map ( ( option ) => (
106+ < MenuItem key = { option . value } value = { option . value } >
107+ { option . label }
108+ </ MenuItem >
109+ ) ) }
110+ </ Select >
111+ </ div >
112+ ) ;
113+ } ) }
63114
64- const handleClose = ( ) => {
65- setAnchorEl ( null ) ;
66- setOpen ( false ) ;
67- } ;
115+ < div style = { { display : 'flex' , justifyContent : 'center' } } >
116+ < Button variant = "contained" onClick = { handleApplyOnClick } >
117+ Apply
118+ </ Button >
119+ </ div >
120+ </ div >
121+ ) ;
68122
69123 return (
70- < React . Fragment >
124+ < >
71125 < div id = { id } >
72126 < TooltipIcon
73127 title = "Filter"
74128 onClick = { handleClick }
75129 icon = { < FilterIcon fill = { theme . palette . icon . default } /> }
76130 arrow
77131 />
78- < PopperListener
79- id = { idx }
80- open = { open }
81- anchorEl = { anchorEl }
82- placement = "bottom-end"
83- // transition
84- >
85- < div >
86- < ClickAwayListener
87- onClickAway = { handleClose }
88- mouseEvent = "onMouseDown"
89- touchEvent = "onTouchStart"
90- >
91- < div >
92- < Paper
93- sx = { {
94- padding : '1rem' ,
95- paddingTop : '1.8rem' ,
96- boxShadow : '0px 4px 8px rgba(0, 0, 0, 0.1)' ,
97- backgroundColor : theme . palette . background . surfaces
98- } }
99- >
100- { Object . keys ( filters ) . map ( ( filterColumn ) => {
101- const options = filters [ filterColumn ] . options ;
102- return (
103- < div key = { filterColumn } role = "presentation" >
104- < InputLabel id = { filters [ filterColumn ] . name } >
105- { filters [ filterColumn ] . name }
106- </ InputLabel >
107- < Select
108- defaultValue = "All"
109- key = { filterColumn }
110- value = { selectedFilters [ filterColumn ] }
111- variant = { variant }
112- onChange = { ( e : SelectChangeEvent < unknown > ) =>
113- handleFilterChange (
114- e as React . ChangeEvent < { value : string } > ,
115- filterColumn
116- )
117- }
118- style = { {
119- width : '15rem' ,
120- marginBottom : '1rem'
121- } }
122- inputProps = { { 'aria-label' : 'Without label' } }
123- displayEmpty
124- >
125- { showAllOption && < MenuItem value = "All" > All</ MenuItem > }
126- { options . map ( ( option ) => (
127- < MenuItem key = { option . value } value = { option . value } >
128- { option . label }
129- </ MenuItem >
130- ) ) }
131- </ Select >
132- </ div >
133- ) ;
134- } ) }
135-
136- < div style = { { display : 'flex' , justifyContent : 'flex-end' } } >
137- < Button variant = "contained" onClick = { handleApplyOnClick } >
138- Apply
139- </ Button >
140- </ div >
141- </ Paper >
142- </ div >
132+ { ! isMobile ? (
133+ < PopperListener
134+ id = { open && anchorEl ? 'transition-popper' : undefined }
135+ open = { open }
136+ anchorEl = { anchorEl }
137+ placement = "bottom-end"
138+ >
139+ < ClickAwayListener onClickAway = { handleClose } >
140+ < Paper
141+ sx = { {
142+ padding : '1rem' ,
143+ paddingTop : '1.8rem' ,
144+ boxShadow : '0px 4px 8px rgba(0, 0, 0, 0.1)' ,
145+ backgroundColor : theme . palette . background . surfaces
146+ } }
147+ >
148+ { renderFilterContent ( ) }
149+ </ Paper >
143150 </ ClickAwayListener >
144- </ div >
145- </ PopperListener >
151+ </ PopperListener >
152+ ) : (
153+ < Drawer
154+ anchor = "bottom"
155+ open = { open }
156+ onClose = { handleClose }
157+ PaperProps = { {
158+ style : {
159+ padding : '0 1rem 1rem 1rem' ,
160+ backgroundColor : theme . palette . background . surfaces
161+ }
162+ } }
163+ >
164+ { renderFilterContent ( ) }
165+ </ Drawer >
166+ ) }
146167 </ div >
147- </ React . Fragment >
168+ </ >
148169 ) ;
149170}
150171export default UniversalFilter ;
0 commit comments