Move userbar to separate component
This commit is contained in:
parent
ed3d168d22
commit
a7c65f77e4
3 changed files with 164 additions and 126 deletions
|
@ -1,24 +1,14 @@
|
||||||
import Avatar from "@material-ui/core/Avatar";
|
|
||||||
import Chip from "@material-ui/core/Chip";
|
|
||||||
import ClickAwayListener from "@material-ui/core/ClickAwayListener";
|
|
||||||
import Grow from "@material-ui/core/Grow";
|
|
||||||
import Hidden from "@material-ui/core/Hidden";
|
import Hidden from "@material-ui/core/Hidden";
|
||||||
import LinearProgress from "@material-ui/core/LinearProgress";
|
import LinearProgress from "@material-ui/core/LinearProgress";
|
||||||
import MenuItem from "@material-ui/core/MenuItem";
|
|
||||||
import Menu from "@material-ui/core/MenuList";
|
|
||||||
import Paper from "@material-ui/core/Paper";
|
|
||||||
import Popper from "@material-ui/core/Popper";
|
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import { createConfigurationMenu } from "@saleor/configuration";
|
import { createConfigurationMenu } from "@saleor/configuration";
|
||||||
import useAppState from "@saleor/hooks/useAppState";
|
import useAppState from "@saleor/hooks/useAppState";
|
||||||
import useNavigator from "@saleor/hooks/useNavigator";
|
import useNavigator from "@saleor/hooks/useNavigator";
|
||||||
import useTheme from "@saleor/hooks/useTheme";
|
import useTheme from "@saleor/hooks/useTheme";
|
||||||
import useUser from "@saleor/hooks/useUser";
|
import useUser from "@saleor/hooks/useUser";
|
||||||
import ArrowDropdown from "@saleor/icons/ArrowDropdown";
|
|
||||||
import { staffMemberDetailsUrl } from "@saleor/staff/urls";
|
import { staffMemberDetailsUrl } from "@saleor/staff/urls";
|
||||||
import classNames from "classnames";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
import useRouter from "use-react-router";
|
import useRouter from "use-react-router";
|
||||||
|
|
||||||
import Container from "../Container";
|
import Container from "../Container";
|
||||||
|
@ -26,6 +16,7 @@ import ErrorPage from "../ErrorPage";
|
||||||
import Navigator from "../Navigator";
|
import Navigator from "../Navigator";
|
||||||
import NavigatorButton from "../NavigatorButton/NavigatorButton";
|
import NavigatorButton from "../NavigatorButton/NavigatorButton";
|
||||||
import SideBar from "../SideBar";
|
import SideBar from "../SideBar";
|
||||||
|
import UserChip from "../UserChip";
|
||||||
import AppActionContext from "./AppActionContext";
|
import AppActionContext from "./AppActionContext";
|
||||||
import AppHeaderContext from "./AppHeaderContext";
|
import AppHeaderContext from "./AppHeaderContext";
|
||||||
import { appLoaderHeight } from "./consts";
|
import { appLoaderHeight } from "./consts";
|
||||||
|
@ -53,16 +44,7 @@ const useStyles = makeStyles(
|
||||||
height: appLoaderHeight,
|
height: appLoaderHeight,
|
||||||
marginBottom: theme.spacing(4)
|
marginBottom: theme.spacing(4)
|
||||||
},
|
},
|
||||||
arrow: {
|
|
||||||
marginLeft: theme.spacing(2),
|
|
||||||
transition: theme.transitions.duration.standard + "ms"
|
|
||||||
},
|
|
||||||
avatar: {
|
|
||||||
"&&": {
|
|
||||||
height: 32,
|
|
||||||
width: 32
|
|
||||||
}
|
|
||||||
},
|
|
||||||
content: {
|
content: {
|
||||||
flex: 1
|
flex: 1
|
||||||
},
|
},
|
||||||
|
@ -80,16 +62,11 @@ const useStyles = makeStyles(
|
||||||
height: 40,
|
height: 40,
|
||||||
marginBottom: theme.spacing(3)
|
marginBottom: theme.spacing(3)
|
||||||
},
|
},
|
||||||
popover: {
|
|
||||||
zIndex: 1
|
|
||||||
},
|
|
||||||
root: {
|
root: {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
width: `100%`
|
width: `100%`
|
||||||
},
|
},
|
||||||
rotate: {
|
|
||||||
transform: "rotate(180deg)"
|
|
||||||
},
|
|
||||||
spacer: {
|
spacer: {
|
||||||
flex: 1
|
flex: 1
|
||||||
},
|
},
|
||||||
|
@ -97,19 +74,7 @@ const useStyles = makeStyles(
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
display: "flex"
|
display: "flex"
|
||||||
},
|
},
|
||||||
userChip: {
|
|
||||||
backgroundColor: theme.palette.background.paper,
|
|
||||||
borderRadius: 24,
|
|
||||||
color: theme.palette.text.primary,
|
|
||||||
height: 40,
|
|
||||||
padding: theme.spacing(0.5)
|
|
||||||
},
|
|
||||||
userMenuContainer: {
|
|
||||||
position: "relative"
|
|
||||||
},
|
|
||||||
userMenuItem: {
|
|
||||||
textAlign: "right"
|
|
||||||
},
|
|
||||||
view: {
|
view: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
|
@ -135,10 +100,8 @@ interface AppLayoutProps {
|
||||||
const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
|
const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
|
||||||
const classes = useStyles({});
|
const classes = useStyles({});
|
||||||
const { isDark, toggleTheme } = useTheme();
|
const { isDark, toggleTheme } = useTheme();
|
||||||
const [isMenuOpened, setMenuState] = React.useState(false);
|
|
||||||
const appActionAnchor = React.useRef<HTMLDivElement>();
|
const appActionAnchor = React.useRef<HTMLDivElement>();
|
||||||
const appHeaderAnchor = React.useRef<HTMLDivElement>();
|
const appHeaderAnchor = React.useRef<HTMLDivElement>();
|
||||||
const anchor = React.useRef<HTMLDivElement>();
|
|
||||||
const { logout, user } = useUser();
|
const { logout, user } = useUser();
|
||||||
const navigate = useNavigator();
|
const navigate = useNavigator();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
@ -159,16 +122,6 @@ const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleLogout = () => {
|
|
||||||
setMenuState(false);
|
|
||||||
logout();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleViewerProfile = () => {
|
|
||||||
setMenuState(false);
|
|
||||||
navigate(staffMemberDetailsUrl(user.id));
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleErrorBack = () => {
|
const handleErrorBack = () => {
|
||||||
navigate("/");
|
navigate("/");
|
||||||
dispatchAppState({
|
dispatchAppState({
|
||||||
|
@ -224,80 +177,13 @@ const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
|
||||||
.includes("mac")}
|
.includes("mac")}
|
||||||
onClick={() => setNavigatorVisibility(true)}
|
onClick={() => setNavigatorVisibility(true)}
|
||||||
/>
|
/>
|
||||||
<div className={classes.userMenuContainer} ref={anchor}>
|
<UserChip
|
||||||
<Chip
|
onLogout={logout}
|
||||||
avatar={
|
onProfileClick={() =>
|
||||||
user.avatar && (
|
navigate(staffMemberDetailsUrl(user.id))
|
||||||
<Avatar alt="user" src={user.avatar.url} />
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
classes={{
|
user={user}
|
||||||
avatar: classes.avatar
|
|
||||||
}}
|
|
||||||
className={classes.userChip}
|
|
||||||
label={
|
|
||||||
<>
|
|
||||||
{user.email}
|
|
||||||
<ArrowDropdown
|
|
||||||
className={classNames(classes.arrow, {
|
|
||||||
[classes.rotate]: isMenuOpened
|
|
||||||
})}
|
|
||||||
/>
|
/>
|
||||||
</>
|
|
||||||
}
|
|
||||||
onClick={() => setMenuState(!isMenuOpened)}
|
|
||||||
data-test="userMenu"
|
|
||||||
/>
|
|
||||||
<Popper
|
|
||||||
className={classes.popover}
|
|
||||||
open={isMenuOpened}
|
|
||||||
anchorEl={anchor.current}
|
|
||||||
transition
|
|
||||||
placement="bottom-end"
|
|
||||||
>
|
|
||||||
{({ TransitionProps, placement }) => (
|
|
||||||
<Grow
|
|
||||||
{...TransitionProps}
|
|
||||||
style={{
|
|
||||||
transformOrigin:
|
|
||||||
placement === "bottom"
|
|
||||||
? "right top"
|
|
||||||
: "right bottom"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Paper>
|
|
||||||
<ClickAwayListener
|
|
||||||
onClickAway={() => setMenuState(false)}
|
|
||||||
mouseEvent="onClick"
|
|
||||||
>
|
|
||||||
<Menu>
|
|
||||||
<MenuItem
|
|
||||||
className={classes.userMenuItem}
|
|
||||||
onClick={handleViewerProfile}
|
|
||||||
data-test="accountSettingsButton"
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Account Settings"
|
|
||||||
description="button"
|
|
||||||
/>
|
|
||||||
</MenuItem>
|
|
||||||
<MenuItem
|
|
||||||
className={classes.userMenuItem}
|
|
||||||
onClick={handleLogout}
|
|
||||||
data-test="logOutButton"
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Log out"
|
|
||||||
description="button"
|
|
||||||
/>
|
|
||||||
</MenuItem>
|
|
||||||
</Menu>
|
|
||||||
</ClickAwayListener>
|
|
||||||
</Paper>
|
|
||||||
</Grow>
|
|
||||||
)}
|
|
||||||
</Popper>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Hidden mdUp>
|
<Hidden mdUp>
|
||||||
|
|
150
src/components/UserChip/UserChip.tsx
Normal file
150
src/components/UserChip/UserChip.tsx
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
import Avatar from "@material-ui/core/Avatar";
|
||||||
|
import Chip from "@material-ui/core/Chip";
|
||||||
|
import ClickAwayListener from "@material-ui/core/ClickAwayListener";
|
||||||
|
import Grow from "@material-ui/core/Grow";
|
||||||
|
import MenuItem from "@material-ui/core/MenuItem";
|
||||||
|
import Menu from "@material-ui/core/MenuList";
|
||||||
|
import Paper from "@material-ui/core/Paper";
|
||||||
|
import Popper from "@material-ui/core/Popper";
|
||||||
|
import makeStyles from "@material-ui/core/styles/makeStyles";
|
||||||
|
import { User } from "@saleor/fragments/types/User";
|
||||||
|
import ArrowDropdown from "@saleor/icons/ArrowDropdown";
|
||||||
|
import classNames from "classnames";
|
||||||
|
import React from "react";
|
||||||
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
theme => ({
|
||||||
|
arrow: {
|
||||||
|
marginLeft: theme.spacing(2),
|
||||||
|
transition: theme.transitions.duration.standard + "ms"
|
||||||
|
},
|
||||||
|
avatar: {
|
||||||
|
"&&": {
|
||||||
|
height: 32,
|
||||||
|
width: 32
|
||||||
|
}
|
||||||
|
},
|
||||||
|
popover: {
|
||||||
|
zIndex: 1
|
||||||
|
},
|
||||||
|
rotate: {
|
||||||
|
transform: "rotate(180deg)"
|
||||||
|
},
|
||||||
|
userChip: {
|
||||||
|
backgroundColor: theme.palette.background.paper,
|
||||||
|
borderRadius: 24,
|
||||||
|
color: theme.palette.text.primary,
|
||||||
|
height: 40,
|
||||||
|
padding: theme.spacing(0.5)
|
||||||
|
},
|
||||||
|
userMenuContainer: {
|
||||||
|
position: "relative"
|
||||||
|
},
|
||||||
|
userMenuItem: {
|
||||||
|
textAlign: "right"
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
name: "UserChip"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export interface UserChipProps {
|
||||||
|
user: User;
|
||||||
|
onLogout: () => void;
|
||||||
|
onProfileClick: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UserChip: React.FC<UserChipProps> = ({
|
||||||
|
user,
|
||||||
|
onLogout,
|
||||||
|
onProfileClick
|
||||||
|
}) => {
|
||||||
|
const classes = useStyles({});
|
||||||
|
const [isMenuOpened, setMenuState] = React.useState(false);
|
||||||
|
const anchor = React.useRef<HTMLDivElement>();
|
||||||
|
|
||||||
|
const handleLogout = () => {
|
||||||
|
setMenuState(false);
|
||||||
|
onLogout();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleViewerProfile = () => {
|
||||||
|
setMenuState(false);
|
||||||
|
onProfileClick();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.userMenuContainer} ref={anchor}>
|
||||||
|
<Chip
|
||||||
|
avatar={user.avatar && <Avatar alt="user" src={user.avatar.url} />}
|
||||||
|
classes={{
|
||||||
|
avatar: classes.avatar
|
||||||
|
}}
|
||||||
|
className={classes.userChip}
|
||||||
|
label={
|
||||||
|
<>
|
||||||
|
{user.email}
|
||||||
|
<ArrowDropdown
|
||||||
|
className={classNames(classes.arrow, {
|
||||||
|
[classes.rotate]: isMenuOpened
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
onClick={() => setMenuState(!isMenuOpened)}
|
||||||
|
data-test="userMenu"
|
||||||
|
/>
|
||||||
|
<Popper
|
||||||
|
className={classes.popover}
|
||||||
|
open={isMenuOpened}
|
||||||
|
anchorEl={anchor.current}
|
||||||
|
transition
|
||||||
|
placement="bottom-end"
|
||||||
|
>
|
||||||
|
{({ TransitionProps, placement }) => (
|
||||||
|
<Grow
|
||||||
|
{...TransitionProps}
|
||||||
|
style={{
|
||||||
|
transformOrigin:
|
||||||
|
placement === "bottom" ? "right top" : "right bottom"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Paper>
|
||||||
|
<ClickAwayListener
|
||||||
|
onClickAway={() => setMenuState(false)}
|
||||||
|
mouseEvent="onClick"
|
||||||
|
>
|
||||||
|
<Menu>
|
||||||
|
<MenuItem
|
||||||
|
className={classes.userMenuItem}
|
||||||
|
onClick={handleViewerProfile}
|
||||||
|
data-test="accountSettingsButton"
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Account Settings"
|
||||||
|
description="button"
|
||||||
|
/>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem
|
||||||
|
className={classes.userMenuItem}
|
||||||
|
onClick={handleLogout}
|
||||||
|
data-test="logOutButton"
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Log out"
|
||||||
|
description="button"
|
||||||
|
/>
|
||||||
|
</MenuItem>
|
||||||
|
</Menu>
|
||||||
|
</ClickAwayListener>
|
||||||
|
</Paper>
|
||||||
|
</Grow>
|
||||||
|
)}
|
||||||
|
</Popper>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
UserChip.displayName = "UserChip";
|
||||||
|
export default UserChip;
|
2
src/components/UserChip/index.ts
Normal file
2
src/components/UserChip/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export * from "./UserChip";
|
||||||
|
export { default } from "./UserChip";
|
Loading…
Reference in a new issue