2019-06-19 14:40:52 +00:00
|
|
|
import LinearProgress from "@material-ui/core/LinearProgress";
|
2020-11-18 15:11:15 +00:00
|
|
|
import useMediaQuery from "@material-ui/core/useMediaQuery";
|
2019-10-09 15:14:23 +00:00
|
|
|
import { createConfigurationMenu } from "@saleor/configuration";
|
2019-11-14 14:10:52 +00:00
|
|
|
import useAppState from "@saleor/hooks/useAppState";
|
2019-06-19 14:40:52 +00:00
|
|
|
import useNavigator from "@saleor/hooks/useNavigator";
|
|
|
|
import useTheme from "@saleor/hooks/useTheme";
|
|
|
|
import useUser from "@saleor/hooks/useUser";
|
2019-10-25 12:54:14 +00:00
|
|
|
import { staffMemberDetailsUrl } from "@saleor/staff/urls";
|
2021-03-30 07:40:18 +00:00
|
|
|
import { makeStyles, SaleorTheme } from "@saleor/theme";
|
2020-09-25 14:38:59 +00:00
|
|
|
import classNames from "classnames";
|
2020-05-14 09:30:32 +00:00
|
|
|
import React from "react";
|
2020-11-18 15:11:15 +00:00
|
|
|
import { useIntl } from "react-intl";
|
2020-05-14 09:30:32 +00:00
|
|
|
import useRouter from "use-react-router";
|
|
|
|
|
2019-06-19 14:40:52 +00:00
|
|
|
import Container from "../Container";
|
2019-11-14 14:10:52 +00:00
|
|
|
import ErrorPage from "../ErrorPage";
|
2020-08-08 12:59:09 +00:00
|
|
|
import Navigator from "../Navigator";
|
2020-08-10 12:43:24 +00:00
|
|
|
import NavigatorButton from "../NavigatorButton/NavigatorButton";
|
2020-11-18 15:11:15 +00:00
|
|
|
import SideBar from "../SideBar";
|
|
|
|
import SideBarDrawer from "../SideBarDrawer/SideBarDrawer";
|
|
|
|
import UserChip from "../UserChip";
|
2019-06-19 14:40:52 +00:00
|
|
|
import AppActionContext from "./AppActionContext";
|
2020-11-23 09:39:24 +00:00
|
|
|
import useAppChannel from "./AppChannelContext";
|
|
|
|
import AppChannelSelect from "./AppChannelSelect";
|
2019-06-19 14:40:52 +00:00
|
|
|
import AppHeaderContext from "./AppHeaderContext";
|
2020-11-18 15:11:15 +00:00
|
|
|
import { appLoaderHeight } from "./consts";
|
2019-08-29 10:55:56 +00:00
|
|
|
import createMenuStructure from "./menuStructure";
|
2019-06-19 14:40:52 +00:00
|
|
|
|
2019-10-30 14:34:24 +00:00
|
|
|
const useStyles = makeStyles(
|
|
|
|
theme => ({
|
2019-06-19 14:40:52 +00:00
|
|
|
appAction: {
|
2019-10-22 11:32:45 +00:00
|
|
|
[theme.breakpoints.down("sm")]: {
|
|
|
|
left: 0,
|
|
|
|
width: "100%"
|
|
|
|
},
|
2019-06-19 14:40:52 +00:00
|
|
|
bottom: 0,
|
|
|
|
gridColumn: 2,
|
2019-10-23 15:10:46 +00:00
|
|
|
position: "sticky",
|
2019-09-16 02:14:57 +00:00
|
|
|
zIndex: 10
|
2019-06-19 14:40:52 +00:00
|
|
|
},
|
2020-10-14 08:17:23 +00:00
|
|
|
appActionDocked: {
|
|
|
|
position: "static"
|
|
|
|
},
|
2019-06-19 14:40:52 +00:00
|
|
|
appLoader: {
|
|
|
|
height: appLoaderHeight,
|
2020-11-18 15:11:15 +00:00
|
|
|
marginBottom: theme.spacing(4),
|
2019-06-19 14:40:52 +00:00
|
|
|
zIndex: 1201
|
|
|
|
},
|
2019-10-23 15:10:46 +00:00
|
|
|
appLoaderPlaceholder: {
|
|
|
|
height: appLoaderHeight,
|
2020-11-18 15:11:15 +00:00
|
|
|
marginBottom: theme.spacing(4)
|
2020-09-25 14:38:59 +00:00
|
|
|
},
|
2020-11-18 15:11:15 +00:00
|
|
|
|
2019-06-19 14:40:52 +00:00
|
|
|
content: {
|
2020-11-18 15:11:15 +00:00
|
|
|
flex: 1
|
2019-06-19 14:40:52 +00:00
|
|
|
},
|
|
|
|
darkThemeSwitch: {
|
2019-11-12 16:28:21 +00:00
|
|
|
[theme.breakpoints.down("sm")]: {
|
2020-11-18 15:11:15 +00:00
|
|
|
marginRight: theme.spacing(1)
|
2019-11-12 16:28:21 +00:00
|
|
|
},
|
2019-10-28 16:16:49 +00:00
|
|
|
marginRight: theme.spacing(2)
|
2019-06-19 14:40:52 +00:00
|
|
|
},
|
|
|
|
header: {
|
2020-11-18 15:11:15 +00:00
|
|
|
display: "grid",
|
|
|
|
gridTemplateAreas: `"headerAnchor headerToolbar"`,
|
2019-11-12 16:28:21 +00:00
|
|
|
[theme.breakpoints.down("sm")]: {
|
2020-11-18 15:11:15 +00:00
|
|
|
gridTemplateAreas: `"headerToolbar"
|
|
|
|
"headerAnchor"`
|
2019-11-12 16:28:21 +00:00
|
|
|
},
|
2020-09-25 15:23:07 +00:00
|
|
|
marginBottom: theme.spacing(3)
|
2019-06-19 14:40:52 +00:00
|
|
|
},
|
2020-11-18 15:11:15 +00:00
|
|
|
headerAnchor: {
|
|
|
|
gridArea: "headerAnchor"
|
2020-09-25 14:45:27 +00:00
|
|
|
},
|
2020-11-18 15:11:15 +00:00
|
|
|
headerToolbar: {
|
|
|
|
display: "flex",
|
|
|
|
gridArea: "headerToolbar",
|
|
|
|
height: 40,
|
2020-09-25 14:45:27 +00:00
|
|
|
[theme.breakpoints.down("sm")]: {
|
2020-11-18 15:11:15 +00:00
|
|
|
height: "auto"
|
2020-09-25 14:45:27 +00:00
|
|
|
}
|
|
|
|
},
|
2019-06-19 14:40:52 +00:00
|
|
|
root: {
|
2020-11-18 15:11:15 +00:00
|
|
|
[theme.breakpoints.up("md")]: {
|
|
|
|
display: "flex"
|
2020-09-25 14:45:27 +00:00
|
|
|
},
|
2020-11-18 15:11:15 +00:00
|
|
|
width: `100%`
|
2020-09-25 14:45:27 +00:00
|
|
|
},
|
2019-06-19 14:40:52 +00:00
|
|
|
spacer: {
|
|
|
|
flex: 1
|
|
|
|
},
|
|
|
|
userBar: {
|
|
|
|
alignItems: "center",
|
|
|
|
display: "flex"
|
|
|
|
},
|
2020-11-18 15:11:15 +00:00
|
|
|
|
2019-06-19 14:40:52 +00:00
|
|
|
view: {
|
|
|
|
flex: 1,
|
|
|
|
flexGrow: 1,
|
|
|
|
marginLeft: 0,
|
2019-10-28 16:16:49 +00:00
|
|
|
paddingBottom: theme.spacing(),
|
2019-10-23 15:10:46 +00:00
|
|
|
[theme.breakpoints.up("sm")]: {
|
2019-10-28 16:16:49 +00:00
|
|
|
paddingBottom: theme.spacing(3)
|
2019-10-23 15:10:46 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
viewContainer: {
|
2020-09-25 14:45:27 +00:00
|
|
|
minHeight: `calc(100vh - ${theme.spacing(2) + appLoaderHeight + 70}px)`
|
2019-06-19 14:40:52 +00:00
|
|
|
}
|
2019-10-30 14:34:24 +00:00
|
|
|
}),
|
|
|
|
{
|
|
|
|
name: "AppLayout"
|
|
|
|
}
|
|
|
|
);
|
2019-06-19 14:40:52 +00:00
|
|
|
|
|
|
|
interface AppLayoutProps {
|
|
|
|
children: React.ReactNode;
|
|
|
|
}
|
|
|
|
|
2019-11-14 14:10:52 +00:00
|
|
|
const AppLayout: React.FC<AppLayoutProps> = ({ children }) => {
|
|
|
|
const classes = useStyles({});
|
|
|
|
const { isDark, toggleTheme } = useTheme();
|
|
|
|
const appActionAnchor = React.useRef<HTMLDivElement>();
|
|
|
|
const appHeaderAnchor = React.useRef<HTMLDivElement>();
|
|
|
|
const { logout, user } = useUser();
|
|
|
|
const navigate = useNavigator();
|
|
|
|
const intl = useIntl();
|
|
|
|
const [appState, dispatchAppState] = useAppState();
|
|
|
|
const { location } = useRouter();
|
2020-08-08 12:59:09 +00:00
|
|
|
const [isNavigatorVisible, setNavigatorVisibility] = React.useState(false);
|
2021-03-30 07:40:18 +00:00
|
|
|
const isMdUp = useMediaQuery((theme: SaleorTheme) =>
|
|
|
|
theme.breakpoints.up("md")
|
|
|
|
);
|
2020-10-14 08:17:23 +00:00
|
|
|
const [docked, setDocked] = React.useState(true);
|
2020-11-23 09:39:24 +00:00
|
|
|
const {
|
|
|
|
availableChannels,
|
|
|
|
channel,
|
|
|
|
isPickerActive,
|
|
|
|
setChannel
|
|
|
|
} = useAppChannel(false);
|
2019-08-29 10:55:56 +00:00
|
|
|
|
2019-11-14 14:10:52 +00:00
|
|
|
const menuStructure = createMenuStructure(intl);
|
|
|
|
const configurationMenu = createConfigurationMenu(intl);
|
2020-04-23 15:43:08 +00:00
|
|
|
const userPermissions = user?.userPermissions || [];
|
2019-10-09 15:14:23 +00:00
|
|
|
|
2019-11-14 14:10:52 +00:00
|
|
|
const renderConfigure = configurationMenu.some(section =>
|
|
|
|
section.menuItems.some(
|
|
|
|
menuItem =>
|
|
|
|
!!userPermissions.find(
|
|
|
|
userPermission => userPermission.code === menuItem.permission
|
|
|
|
)
|
|
|
|
)
|
|
|
|
);
|
2019-06-19 14:40:52 +00:00
|
|
|
|
2019-11-14 14:10:52 +00:00
|
|
|
const handleErrorBack = () => {
|
|
|
|
navigate("/");
|
|
|
|
dispatchAppState({
|
|
|
|
payload: {
|
|
|
|
error: null
|
|
|
|
},
|
|
|
|
type: "displayError"
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
return (
|
2020-08-08 12:59:09 +00:00
|
|
|
<>
|
|
|
|
<Navigator
|
|
|
|
visible={isNavigatorVisible}
|
|
|
|
setVisibility={setNavigatorVisibility}
|
|
|
|
/>
|
|
|
|
<AppHeaderContext.Provider value={appHeaderAnchor}>
|
2020-10-14 08:17:23 +00:00
|
|
|
<AppActionContext.Provider
|
|
|
|
value={{
|
|
|
|
anchor: appActionAnchor,
|
|
|
|
docked,
|
|
|
|
setDocked
|
|
|
|
}}
|
|
|
|
>
|
2020-08-08 12:59:09 +00:00
|
|
|
<div className={classes.root}>
|
2020-11-18 15:11:15 +00:00
|
|
|
{isMdUp && (
|
|
|
|
<SideBar
|
|
|
|
menuItems={menuStructure}
|
|
|
|
location={location.pathname}
|
|
|
|
user={user}
|
|
|
|
renderConfigure={renderConfigure}
|
|
|
|
onMenuItemClick={navigate}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
<div className={classes.content}>
|
2020-08-08 12:59:09 +00:00
|
|
|
{appState.loading ? (
|
|
|
|
<LinearProgress className={classes.appLoader} color="primary" />
|
|
|
|
) : (
|
|
|
|
<div className={classes.appLoaderPlaceholder} />
|
|
|
|
)}
|
|
|
|
<div className={classes.viewContainer}>
|
|
|
|
<div>
|
|
|
|
<Container>
|
|
|
|
<div className={classes.header}>
|
2020-09-25 14:45:27 +00:00
|
|
|
<div
|
2020-11-18 15:11:15 +00:00
|
|
|
className={classes.headerAnchor}
|
|
|
|
ref={appHeaderAnchor}
|
|
|
|
/>
|
|
|
|
<div className={classes.headerToolbar}>
|
|
|
|
{!isMdUp && (
|
|
|
|
<SideBarDrawer
|
|
|
|
menuItems={menuStructure}
|
|
|
|
location={location.pathname}
|
|
|
|
user={user}
|
|
|
|
renderConfigure={renderConfigure}
|
|
|
|
onMenuItemClick={navigate}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
<div className={classes.spacer} />
|
|
|
|
<div className={classes.userBar}>
|
2020-09-25 15:27:50 +00:00
|
|
|
<NavigatorButton
|
|
|
|
isMac={navigator.platform
|
|
|
|
.toLowerCase()
|
|
|
|
.includes("mac")}
|
|
|
|
onClick={() => setNavigatorVisibility(true)}
|
|
|
|
/>
|
2021-01-13 09:33:38 +00:00
|
|
|
{channel && (
|
|
|
|
<AppChannelSelect
|
|
|
|
channels={availableChannels}
|
|
|
|
disabled={!isPickerActive}
|
|
|
|
selectedChannelId={channel.id}
|
|
|
|
onChannelSelect={setChannel}
|
|
|
|
/>
|
|
|
|
)}
|
2020-11-18 15:11:15 +00:00
|
|
|
<UserChip
|
2020-11-23 09:39:24 +00:00
|
|
|
isDarkThemeEnabled={isDark}
|
|
|
|
user={user}
|
2020-11-18 15:11:15 +00:00
|
|
|
onLogout={logout}
|
|
|
|
onProfileClick={() =>
|
|
|
|
navigate(staffMemberDetailsUrl(user.id))
|
2020-09-18 13:08:50 +00:00
|
|
|
}
|
2020-11-23 09:39:24 +00:00
|
|
|
onThemeToggle={toggleTheme}
|
2020-09-18 13:08:50 +00:00
|
|
|
/>
|
|
|
|
</div>
|
2019-11-14 14:10:52 +00:00
|
|
|
</div>
|
2019-06-19 14:40:52 +00:00
|
|
|
</div>
|
2020-08-08 12:59:09 +00:00
|
|
|
</Container>
|
|
|
|
</div>
|
|
|
|
<main className={classes.view}>
|
|
|
|
{appState.error
|
2021-01-22 14:05:26 +00:00
|
|
|
? appState.error.type === "unhandled" && (
|
|
|
|
<ErrorPage
|
|
|
|
id={appState.error.id}
|
|
|
|
onBack={handleErrorBack}
|
|
|
|
/>
|
2020-08-08 12:59:09 +00:00
|
|
|
)
|
|
|
|
: children}
|
|
|
|
</main>
|
2019-10-30 14:34:24 +00:00
|
|
|
</div>
|
2020-10-14 08:17:23 +00:00
|
|
|
<div
|
|
|
|
className={classNames(classes.appAction, {
|
|
|
|
[classes.appActionDocked]: docked
|
|
|
|
})}
|
|
|
|
ref={appActionAnchor}
|
|
|
|
/>
|
2019-11-14 14:10:52 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
2020-08-08 12:59:09 +00:00
|
|
|
</AppActionContext.Provider>
|
|
|
|
</AppHeaderContext.Provider>
|
|
|
|
</>
|
2019-11-14 14:10:52 +00:00
|
|
|
);
|
|
|
|
};
|
2019-06-19 14:40:52 +00:00
|
|
|
|
|
|
|
export default AppLayout;
|