diff --git a/src/app.js b/src/app.js index 612f8745b..3c1811a2a 100644 --- a/src/app.js +++ b/src/app.js @@ -30,8 +30,14 @@ import { } from "openstack-uicore-foundation/lib/security/methods"; import IdTokenVerifier from "idtoken-verifier"; import T from "i18n-react"; +import { Breadcrumbs } from "react-breadcrumbs"; import { LocalizationProvider } from "@mui/x-date-pickers"; import { AdapterMoment } from "@mui/x-date-pickers/AdapterMoment"; +import AppBar from "@mui/material/AppBar"; +import Toolbar from "@mui/material/Toolbar"; +import Typography from "@mui/material/Typography"; +import IconButton from "@mui/material/IconButton"; +import MenuIcon from "@mui/icons-material/Menu"; // eslint-disable-next-line import * as Sentry from "@sentry/react"; import exclusiveSections from "./exclusive-sections.yml"; @@ -116,6 +122,8 @@ if (exclusiveSections.hasOwnProperty(process.env.APP_CLIENT_NAME)) { window.EXCLUSIVE_SECTIONS = exclusiveSections[process.env.APP_CLIENT_NAME]; } +const MENU_CLOSE_DELAY_MS = 200; + if (window.SENTRY_DSN && window.SENTRY_DSN !== "") { console.log("app init sentry ..."); // Initialize Sentry @@ -146,6 +154,12 @@ class App extends React.PureComponent { constructor(props) { super(props); props.resetLoading(); + this.state = { menuOpen: false }; + this.menuCloseTimeout = null; + this.toggleMenu = this.toggleMenu.bind(this); + this.openMenu = this.openMenu.bind(this); + this.cancelMenuClose = this.cancelMenuClose.bind(this); + this.scheduleMenuClose = this.scheduleMenuClose.bind(this); } onClickLogin() { @@ -156,6 +170,34 @@ class App extends React.PureComponent { this.props.getTimezones(); } + componentWillUnmount() { + this.cancelMenuClose(); + } + + toggleMenu() { + this.cancelMenuClose(); + this.setState((prevState) => ({ menuOpen: !prevState.menuOpen })); + } + + openMenu() { + this.cancelMenuClose(); + this.setState({ menuOpen: true }); + } + + cancelMenuClose() { + if (this.menuCloseTimeout) { + clearTimeout(this.menuCloseTimeout); + this.menuCloseTimeout = null; + } + } + + scheduleMenuClose() { + this.cancelMenuClose(); + this.menuCloseTimeout = setTimeout(() => { + this.setState({ menuOpen: false }); + }, MENU_CLOSE_DELAY_MS); + } + render() { const { isLoggedUser, @@ -165,6 +207,7 @@ class App extends React.PureComponent { backUrl, loading } = this.props; + const { menuOpen } = this.state; const idToken = getIdToken(); @@ -188,23 +231,87 @@ class App extends React.PureComponent {
- + + + {isLoggedUser && ( + + + + )} + + {T.translate("landing.os_summit_admin")} + + {isLoggedUser && ( + + )} + + {isLoggedUser && ( + + + + )} + + {!isLoggedUser && ( + + )} { + if (isLoggedUser) { + return ( + + ); } - toggleLogOut(ev) { - this.setState({ showLogOut: !this.state.showLogOut }); - } + return ( +
+ {T.translate("landing.not_logged_in")} +
+
+ +
+ ); +}; - render() { - let { isLoggedUser, doLogin, initLogOut, picture } = this.props; - let { showLogOut } = this.state; - - if (isLoggedUser) { - return ( -
-
- {showLogOut && ( - - )} -
- ); - } else { - return ( -
- {T.translate("landing.not_logged_in")} -
-
- -
- ); - } - } -} +export default AuthButton; diff --git a/src/components/menu/index.js b/src/components/menu/index.js index 2ad078c55..389b8f6d6 100644 --- a/src/components/menu/index.js +++ b/src/components/menu/index.js @@ -11,29 +11,36 @@ * limitations under the License. * */ -import React, { useState } from "react"; +import React from "react"; import T from "i18n-react/dist/i18n-react"; import { withRouter } from "react-router-dom"; import Box from "@mui/material/Box"; +import Drawer from "@mui/material/Drawer"; import Divider from "@mui/material/Divider"; -import IconButton from "@mui/material/IconButton"; -import MenuIcon from "@mui/icons-material/Menu"; -import ChevronRightIcon from "@mui/icons-material/ChevronRight"; import SubMenuItem from "./sub-menu-item"; import MenuItem from "./menu-item"; import ExpandableItem from "./expandable-item"; import Member from "../../models/member"; import { getGlobalItems, getSummitItems } from "./menu-definition"; -import styles from "./menu.module.less"; +const DRAWER_WIDTH = 260; -const Menu = ({ currentSummit, member, history }) => { - const [menuOpen, setMenuOpen] = useState(false); +const Menu = ({ + currentSummit, + member, + history, + menuOpen, + toggleMenu, + onMenuMouseEnter, + onMenuMouseLeave +}) => { const memberObj = new Member(member); const globalItems = getGlobalItems(); const summitItems = currentSummit ? getSummitItems(currentSummit.id) : []; - const closeMenu = () => setMenuOpen(false); + const closeMenu = () => { + if (menuOpen) toggleMenu(); + }; const onMenuItemClick = (ev, url) => { ev.preventDefault(); @@ -73,52 +80,37 @@ const Menu = ({ currentSummit, member, history }) => { }; return ( - <> - {menuOpen && ( - - )} + - - (menuOpen ? closeMenu() : setMenuOpen(true))} - > - - - - setMenuOpen(true)} - onMouseLeave={() => setMenuOpen(false)} - > - - - + + {globalItems.map(drawMenuItem)} + - - - {globalItems.map(drawMenuItem)} + {!!currentSummit?.id && ( + <> + + + {summitItems.map(drawMenuItem)} - - {!!currentSummit?.id && ( - <> - - - {summitItems.map(drawMenuItem)} - - - )} - - + + )} - + ); }; diff --git a/src/components/menu/menu.module.less b/src/components/menu/menu.module.less deleted file mode 100644 index 5664cc2d9..000000000 --- a/src/components/menu/menu.module.less +++ /dev/null @@ -1,85 +0,0 @@ -.wrapper { - top: 0; - left: 0; - position: fixed; - height: 100vh; - z-index: 99999; - - &.opened { - .burgerButton { - display: none; - } - - .expandButton { - display: none; - } - - .menuWrapper { - width: 260px; - } - - .menuItemsWrapper { - visibility: visible; - } - } - - &.closed { - overflow-y: hidden; - .burgerButton { - display: block; - pointer-events: auto; - - @media (min-width: 768px) { - display: none; - } - } - - .menuWrapper { - width: 0; - - .expandButton { - display: none; - } - - @media (min-width: 768px) { - width: 40px; - - .menuItemsWrapper { - visibility: hidden; - } - - .expandButton { - display: flex; - } - } - } - @media (max-width: 768px) { - pointer-events: none; - } - } - - .menuWrapper { - background-color: #ffffff; - border-right: 1px solid #e0e0e0; - cursor: pointer; - transition: width 200ms linear; - height: 100%; - - .expandButton { - justify-content: center; - align-items: center; - height: 100%; - } - - .menuItemsWrapper { - padding-bottom: 20px; - transition: visibility 200ms linear 200ms; - overflow-y: auto; - height: 100%; - } - } - - .burgerButton { - padding: 5px 0 0 5px; - } -} diff --git a/src/i18n/en.json b/src/i18n/en.json index be86b43e0..4bdae4e1c 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -139,6 +139,7 @@ "not_logged_in": "You are not logged in. Please log in to continue:" }, "menu": { + "toggle_navigation": "Toggle navigation menu", "general": "General", "directory": "Directory", "dashboard": "Dashboard", diff --git a/src/layouts/primary-layout.js b/src/layouts/primary-layout.js index cddc1f409..23b8d1b75 100644 --- a/src/layouts/primary-layout.js +++ b/src/layouts/primary-layout.js @@ -14,7 +14,7 @@ import React, { Suspense } from "react"; import { connect } from "react-redux"; import { Switch, Route, Redirect } from "react-router-dom"; -import { Breadcrumbs, Breadcrumb } from "react-breadcrumbs"; +import { Breadcrumb } from "react-breadcrumbs"; import AjaxLoader from "openstack-uicore-foundation/lib/components/ajaxloader"; import Restrict from "../routes/restrict"; import Menu from "../components/menu"; @@ -42,72 +42,64 @@ const AddOnTypesListPage = React.lazy(() => import("../pages/sponsors-global/add-on-types/add-on-types-list-page") ); -const PrimaryLayout = ({ match, currentSummit, location, member }) => { - let extraClass = "container"; +const PrimaryLayout = ({ + match, + currentSummit, + member, + menuOpen, + toggleMenu, + onMenuMouseEnter, + onMenuMouseLeave +}) => ( +
+ +
+ , pathname: match.url }} + /> - // full width pages - if ( - location.pathname.includes("schedule") || - location.pathname.includes("bulk-actions") - ) { - extraClass = ""; - } - - return ( -
- -
- - - , pathname: match.url }} - /> - - }> - - - - - - - - - - - - - - - - } /> - - -
-
- ); -}; + }> + + + + + + + + + + + + + + + + } /> + + +
+
+); const mapStateToProps = ({ currentSummitState, loggedUserState }) => ({ currentSummit: currentSummitState.currentSummit, diff --git a/src/layouts/summit-id-layout.js b/src/layouts/summit-id-layout.js index 816bc92b7..b6a839aa0 100644 --- a/src/layouts/summit-id-layout.js +++ b/src/layouts/summit-id-layout.js @@ -144,7 +144,7 @@ const SummitIdLayout = ({ currentSummit, loading, match, ...props }) => { return null; return ( -
+
}> diff --git a/src/pages/summits/summit-dashboard-page.js b/src/pages/summits/summit-dashboard-page.js index 21e5fb931..0fbc5ee3d 100644 --- a/src/pages/summits/summit-dashboard-page.js +++ b/src/pages/summits/summit-dashboard-page.js @@ -16,7 +16,6 @@ import { connect } from "react-redux"; import T from "i18n-react/dist/i18n-react"; import { Breadcrumb } from "react-breadcrumbs"; import Box from "@mui/material/Box"; -import Container from "@mui/material/Container"; import Grid2 from "@mui/material/Grid2"; import Stack from "@mui/material/Stack"; import Tab from "@mui/material/Tab"; @@ -61,7 +60,7 @@ function SummitDashboardPage({ ).length; return ( - +
)} - +
); } diff --git a/src/routes/authorized-route.js b/src/routes/authorized-route.js index e4c4a2f7c..dc761bc65 100644 --- a/src/routes/authorized-route.js +++ b/src/routes/authorized-route.js @@ -21,6 +21,7 @@ class AuthorizedRoute extends React.Component { isLoggedUser, backUrl, currentSummit, + componentProps, ...rest } = this.props; return ( @@ -39,7 +40,14 @@ class AuthorizedRoute extends React.Component { } if (isLoggedUser) { - return ; + return ( + + ); } else { return (