2021-05-14 08:15:15 +00:00
|
|
|
import { LinearProgress, useMediaQuery } from "@material-ui/core";
|
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 useUser from "@saleor/hooks/useUser";
|
2021-07-21 08:59:52 +00:00
|
|
|
import {
|
|
|
|
makeStyles,
|
|
|
|
SaleorTheme,
|
|
|
|
Sidebar,
|
|
|
|
SidebarDrawer,
|
2021-10-21 11:25:24 +00:00
|
|
|
useActionBar,
|
2021-07-21 08:59:52 +00:00
|
|
|
useBacklink,
|
|
|
|
useTheme
|
|
|
|
} from "@saleor/macaw-ui";
|
2021-08-16 13:44:00 +00:00
|
|
|
import { isDarkTheme } from "@saleor/misc";
|
2019-10-25 12:54:14 +00:00
|
|
|
import { staffMemberDetailsUrl } from "@saleor/staff/urls";
|
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 UserChip from "../UserChip";
|
2020-11-23 09:39:24 +00:00
|
|
|
import useAppChannel from "./AppChannelContext";
|
|
|
|
import AppChannelSelect from "./AppChannelSelect";
|
2020-11-18 15:11:15 +00:00
|
|
|
import { appLoaderHeight } from "./consts";
|
2019-08-29 10:55:56 +00:00
|
|
|
import createMenuStructure from "./menuStructure";
|
2021-07-21 08:59:52 +00:00
|
|
|
import { isMenuActive } from "./utils";
|
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: {
|
2021-07-21 08:59:52 +00:00
|
|
|
minHeight: `calc(100vh + ${appLoaderHeight + 70}px - ${theme.spacing(2)})`
|
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({});
|
2021-07-21 08:59:52 +00:00
|
|
|
const { themeType, setTheme } = useTheme();
|
2021-10-21 11:25:24 +00:00
|
|
|
const { anchor: appActionAnchor, docked } = useActionBar();
|
2021-07-21 08:59:52 +00:00
|
|
|
const appHeaderAnchor = useBacklink();
|
2019-11-14 14:10:52 +00:00
|
|
|
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-11-23 09:39:24 +00:00
|
|
|
const {
|
|
|
|
availableChannels,
|
|
|
|
channel,
|
|
|
|
isPickerActive,
|
|
|
|
setChannel
|
|
|
|
} = useAppChannel(false);
|
2019-08-29 10:55:56 +00:00
|
|
|
|
2021-07-21 08:59:52 +00:00
|
|
|
const menuStructure = createMenuStructure(intl, user);
|
|
|
|
const activeMenu = menuStructure.find(menuItem =>
|
|
|
|
isMenuActive(location.pathname, menuItem)
|
|
|
|
)?.id;
|
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"
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2021-08-16 13:44:00 +00:00
|
|
|
const toggleTheme = () => setTheme(isDarkTheme(themeType) ? "light" : "dark");
|
2021-07-21 08:59:52 +00:00
|
|
|
|
2019-11-14 14:10:52 +00:00
|
|
|
return (
|
2020-08-08 12:59:09 +00:00
|
|
|
<>
|
|
|
|
<Navigator
|
|
|
|
visible={isNavigatorVisible}
|
|
|
|
setVisibility={setNavigatorVisibility}
|
|
|
|
/>
|
2021-07-21 08:59:52 +00:00
|
|
|
<div className={classes.root}>
|
|
|
|
{isMdUp && (
|
|
|
|
<Sidebar
|
|
|
|
active={activeMenu}
|
|
|
|
menuItems={menuStructure}
|
|
|
|
onMenuItemClick={navigate}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
<div className={classes.content}>
|
|
|
|
{appState.loading ? (
|
|
|
|
<LinearProgress className={classes.appLoader} color="primary" />
|
|
|
|
) : (
|
|
|
|
<div className={classes.appLoaderPlaceholder} />
|
|
|
|
)}
|
|
|
|
<div className={classes.viewContainer}>
|
|
|
|
<div>
|
|
|
|
<Container>
|
|
|
|
<div className={classes.header}>
|
|
|
|
<div className={classes.headerAnchor} ref={appHeaderAnchor} />
|
|
|
|
<div className={classes.headerToolbar}>
|
|
|
|
{!isMdUp && (
|
|
|
|
<SidebarDrawer
|
|
|
|
menuItems={menuStructure}
|
|
|
|
onMenuItemClick={navigate}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
<div className={classes.spacer} />
|
|
|
|
<div className={classes.userBar}>
|
|
|
|
<NavigatorButton
|
|
|
|
isMac={navigator.platform.toLowerCase().includes("mac")}
|
|
|
|
onClick={() => setNavigatorVisibility(true)}
|
|
|
|
/>
|
2021-08-11 11:44:47 +00:00
|
|
|
{isPickerActive && (
|
2021-07-21 08:59:52 +00:00
|
|
|
<AppChannelSelect
|
|
|
|
channels={availableChannels}
|
2021-08-20 11:14:14 +00:00
|
|
|
selectedChannelId={channel?.id}
|
2021-07-21 08:59:52 +00:00
|
|
|
onChannelSelect={setChannel}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
<UserChip
|
2021-08-16 13:44:00 +00:00
|
|
|
isDarkThemeEnabled={isDarkTheme(themeType)}
|
2021-07-21 08:59:52 +00:00
|
|
|
user={user}
|
|
|
|
onLogout={logout}
|
|
|
|
onProfileClick={() =>
|
2021-08-20 11:14:14 +00:00
|
|
|
navigate(staffMemberDetailsUrl(user?.id))
|
2021-07-21 08:59:52 +00:00
|
|
|
}
|
|
|
|
onThemeToggle={toggleTheme}
|
2020-11-18 15:11:15 +00:00
|
|
|
/>
|
2019-06-19 14:40:52 +00:00
|
|
|
</div>
|
2021-07-21 08:59:52 +00:00
|
|
|
</div>
|
2020-08-08 12:59:09 +00:00
|
|
|
</div>
|
2021-07-21 08:59:52 +00:00
|
|
|
</Container>
|
2019-11-14 14:10:52 +00:00
|
|
|
</div>
|
2021-07-21 08:59:52 +00:00
|
|
|
<main className={classes.view}>
|
|
|
|
{appState.error
|
|
|
|
? appState.error.type === "unhandled" && (
|
|
|
|
<ErrorPage
|
|
|
|
id={appState.error.id}
|
|
|
|
onBack={handleErrorBack}
|
|
|
|
/>
|
|
|
|
)
|
|
|
|
: children}
|
|
|
|
</main>
|
2019-11-14 14:10:52 +00:00
|
|
|
</div>
|
2021-07-21 08:59:52 +00:00
|
|
|
<div
|
|
|
|
className={classNames(classes.appAction, {
|
|
|
|
[classes.appActionDocked]: docked
|
|
|
|
})}
|
|
|
|
ref={appActionAnchor}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
2020-08-08 12:59:09 +00:00
|
|
|
</>
|
2019-11-14 14:10:52 +00:00
|
|
|
);
|
|
|
|
};
|
2019-06-19 14:40:52 +00:00
|
|
|
|
|
|
|
export default AppLayout;
|