Contacts: redesign the address book view and add filtering by group.
This is the first step towards fixing #136.master
parent
78e91abcb4
commit
55cae0962d
@ -0,0 +1,66 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
import InboxIcon from "@material-ui/icons/Inbox";
|
||||||
|
import LabelIcon from "@material-ui/icons/LabelOutlined";
|
||||||
|
|
||||||
|
import { List, ListItem, ListSubheader } from "../widgets/List";
|
||||||
|
import { ContactType } from "../pim-types";
|
||||||
|
|
||||||
|
interface ListItemPropsType {
|
||||||
|
name: string | undefined;
|
||||||
|
icon?: React.ReactElement;
|
||||||
|
primaryText: string;
|
||||||
|
filterByGroup: string | undefined;
|
||||||
|
setFilterByGroup: (group: string | undefined) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function SidebarListItem(props: ListItemPropsType) {
|
||||||
|
const { name, icon, primaryText, filterByGroup } = props;
|
||||||
|
|
||||||
|
const handleClick = () => props.setFilterByGroup(name);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ListItem
|
||||||
|
onClick={handleClick}
|
||||||
|
selected={name === filterByGroup}
|
||||||
|
leftIcon={icon}
|
||||||
|
primaryText={primaryText}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PropsType {
|
||||||
|
groups: ContactType[];
|
||||||
|
filterByGroup: string | undefined;
|
||||||
|
setFilterByGroup: (group: string | undefined) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(function Sidebar(props: PropsType) {
|
||||||
|
const { groups, filterByGroup, setFilterByGroup } = props;
|
||||||
|
|
||||||
|
const groupList = [...groups].sort((a, b) => a.fn.localeCompare(b.fn)).map((group) => (
|
||||||
|
<SidebarListItem
|
||||||
|
key={group.uid}
|
||||||
|
name={group.uid}
|
||||||
|
primaryText={group.fn}
|
||||||
|
icon={<LabelIcon />}
|
||||||
|
filterByGroup={filterByGroup}
|
||||||
|
setFilterByGroup={setFilterByGroup}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<List dense>
|
||||||
|
<SidebarListItem
|
||||||
|
name={undefined}
|
||||||
|
primaryText="All"
|
||||||
|
icon={<InboxIcon />}
|
||||||
|
filterByGroup={filterByGroup}
|
||||||
|
setFilterByGroup={setFilterByGroup}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ListSubheader>Groups</ListSubheader>
|
||||||
|
{groupList}
|
||||||
|
</List>
|
||||||
|
);
|
||||||
|
});
|
@ -0,0 +1,64 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
import SearchIcon from "@material-ui/icons/Search";
|
||||||
|
import TextField from "@material-ui/core/TextField";
|
||||||
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
|
import { Transition } from "react-transition-group";
|
||||||
|
import InputAdornment from "@material-ui/core/InputAdornment";
|
||||||
|
|
||||||
|
const transitionTimeout = 300;
|
||||||
|
|
||||||
|
const transitionStyles = {
|
||||||
|
entering: { visibility: "visible", width: "100%", overflow: "hidden" },
|
||||||
|
entered: { visibility: "visible", width: "100%" },
|
||||||
|
exiting: { visibility: "visible", width: "0%", overflow: "hidden" },
|
||||||
|
exited: { visibility: "hidden", width: "0%" },
|
||||||
|
};
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme) => ({
|
||||||
|
button: {
|
||||||
|
marginRight: theme.spacing(1),
|
||||||
|
},
|
||||||
|
textField: {
|
||||||
|
transition: `width ${transitionTimeout}ms`,
|
||||||
|
marginRight: theme.spacing(1),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
interface PropsType {
|
||||||
|
searchTerm: string;
|
||||||
|
setSearchTerm: (term: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Toolbar(props: PropsType) {
|
||||||
|
const { searchTerm, setSearchTerm } = props;
|
||||||
|
|
||||||
|
const showSearchField = true;
|
||||||
|
const classes = useStyles();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ display: "flex", justifyContent: "flex-end", alignItems: "center" }}>
|
||||||
|
<Transition in={showSearchField} timeout={transitionTimeout}>
|
||||||
|
{(state) => (
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
placeholder="Search"
|
||||||
|
value={searchTerm}
|
||||||
|
color="secondary"
|
||||||
|
variant="standard"
|
||||||
|
className={classes.textField}
|
||||||
|
style={transitionStyles[state]}
|
||||||
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
|
InputProps={{
|
||||||
|
startAdornment: (
|
||||||
|
<InputAdornment position="start">
|
||||||
|
<SearchIcon />
|
||||||
|
</InputAdornment>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Transition>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
Loading…
Reference in New Issue