Skip to content

Commit b43a8b9

Browse files
authored
Schema: User filter update (#1897)
* task: autofocus search field on component mount * task: sort user firstname by asc * task: allow default button text override * task: sticky search filter * task: added no users notif when search has no matches * task: added no users notice when filter has no matches
1 parent cedb4ff commit b43a8b9

File tree

1 file changed

+63
-25
lines changed

1 file changed

+63
-25
lines changed

src/shell/components/Filters/UserFilter.tsx

+63-25
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useRef, FC, useState, useMemo, useEffect } from "react";
1+
import { FC, useState, useMemo } from "react";
22
import {
33
Menu,
44
MenuItem,
@@ -8,10 +8,13 @@ import {
88
TextField,
99
InputAdornment,
1010
IconButton,
11+
ListSubheader,
12+
ListItem,
1113
} from "@mui/material";
1214
import SearchIcon from "@mui/icons-material/Search";
1315
import CloseRoundedIcon from "@mui/icons-material/CloseRounded";
1416
import { theme } from "@zesty-io/material";
17+
import { cloneDeep } from "lodash";
1518

1619
import { FilterButton } from "./FilterButton";
1720
import { useGetUsersQuery } from "../../services/accounts";
@@ -20,37 +23,55 @@ import { MD5 } from "../../../utility/md5";
2023
interface UserFilterProps {
2124
value: string;
2225
onChange: (filter: string) => void;
26+
defaultButtonText?: string;
2327
}
24-
export const UserFilter: FC<UserFilterProps> = ({ value, onChange }) => {
28+
export const UserFilter: FC<UserFilterProps> = ({
29+
value,
30+
onChange,
31+
defaultButtonText = "Created By",
32+
}) => {
2533
const [filter, setFilter] = useState("");
2634
const [menuAnchorEl, setMenuAnchorEl] = useState<HTMLButtonElement | null>(
2735
null
2836
);
2937
const isFilterMenuOpen = Boolean(menuAnchorEl);
3038
const { data: users } = useGetUsersQuery();
31-
const searchField = useRef<HTMLInputElement | null>(null);
3239

3340
const filteredUsers = useMemo(() => {
41+
const _users = cloneDeep(users);
42+
43+
const sortedUsers = _users?.sort((a, b) => {
44+
const nameA = a.firstName.toLowerCase();
45+
const nameB = b.firstName.toLowerCase();
46+
47+
if (nameA < nameB) {
48+
return -1;
49+
}
50+
51+
if (nameA > nameB) {
52+
return 1;
53+
}
54+
55+
return 0;
56+
});
57+
3458
if (!filter.length) {
35-
return users;
59+
return sortedUsers;
3660
}
37-
const _filter = filter.toLowerCase();
3861

39-
return users?.filter(
62+
const _filterTerm = filter.toLowerCase();
63+
64+
return sortedUsers?.filter(
4065
(user) =>
41-
user?.firstName?.toLowerCase().includes(_filter) ||
42-
user?.lastName?.toLowerCase().includes(_filter)
66+
user?.firstName?.toLowerCase().includes(_filterTerm) ||
67+
user?.lastName?.toLowerCase().includes(_filterTerm)
4368
);
4469
}, [filter, users]);
4570

46-
useEffect(() => {
47-
searchField.current?.focus();
48-
}, [filteredUsers]);
49-
5071
const activeUserFilter = users?.find((user) => user?.ZUID === value);
5172
const buttonText = activeUserFilter
5273
? `${activeUserFilter.firstName} ${activeUserFilter.lastName}`
53-
: "Created By";
74+
: defaultButtonText;
5475

5576
const handleOpenMenuClick = (e: React.MouseEvent<HTMLButtonElement>) => {
5677
setMenuAnchorEl(e.currentTarget);
@@ -86,26 +107,34 @@ export const UserFilter: FC<UserFilterProps> = ({ value, onChange }) => {
86107
},
87108
},
88109
}}
110+
MenuListProps={{
111+
sx: {
112+
pt: 0,
113+
pb: 1,
114+
},
115+
}}
116+
autoFocus={false}
89117
>
90-
<MenuItem
91-
disableRipple
118+
<ListSubheader
92119
onKeyDown={(e: React.KeyboardEvent) => {
93-
const allowedKeys = ["ArrowUp", "ArrowDown"];
120+
const allowedKeys = ["ArrowUp", "ArrowDown", "Escape"];
94121

95122
if (!allowedKeys.includes(e.key)) {
96123
e.stopPropagation();
97124
}
98125
}}
99126
sx={{
100-
"&:hover": {
101-
backgroundColor: "common.white",
102-
},
103-
"&.Mui-focusVisible": {
104-
backgroundColor: "common.white",
127+
pt: 1,
128+
height: "60px",
129+
display: "flex",
130+
alignItems: "center",
131+
"&:focus-visible": {
132+
outline: "none",
105133
},
106134
}}
107135
>
108136
<TextField
137+
autoFocus
109138
fullWidth
110139
placeholder="Search Users"
111140
value={filter}
@@ -122,15 +151,24 @@ export const UserFilter: FC<UserFilterProps> = ({ value, onChange }) => {
122151
</IconButton>
123152
) : null,
124153
}}
125-
inputProps={{ ref: searchField }}
126154
/>
127-
</MenuItem>
128-
{filteredUsers?.map((user, index) => {
155+
</ListSubheader>
156+
157+
{!filteredUsers?.length && Boolean(filter) && (
158+
<ListItem>
159+
<ListItemText>No users found</ListItemText>
160+
</ListItem>
161+
)}
162+
163+
{filteredUsers?.map((user) => {
129164
return (
130165
<MenuItem
131166
key={user?.ZUID}
132167
onClick={() => handleFilterSelect(user?.ZUID)}
133-
selected={value ? value === user?.ZUID : index === 0}
168+
selected={value && value === user?.ZUID}
169+
sx={{
170+
height: "52px",
171+
}}
134172
>
135173
<ListItemAvatar>
136174
<Avatar

0 commit comments

Comments
 (0)