diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index 77415ad341..0d018124cc 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -36,9 +36,10 @@ "wordInDatabase": "This word is already in the database" }, "appBar": { - "dataEntry": "data entry", - "dataCleanup": "data cleanup", - "statistics": "data statistics" + "dataEntry": "Data Entry", + "dataCleanup": "Data Cleanup", + "statistics": "Data Statistics", + "projectSettings": "Project Settings" }, "login": { "title": "Log In", @@ -77,7 +78,6 @@ }, "userMenu": { "siteSettings": "Site Settings", - "projectSettings": "Project Settings", "userSettings": "User Settings", "logout": "Log Out", "userGuide": "User Guide" diff --git a/src/components/AppBar/AppBarComponent.tsx b/src/components/AppBar/AppBarComponent.tsx index 44b87288f9..eee9b2b0e2 100644 --- a/src/components/AppBar/AppBarComponent.tsx +++ b/src/components/AppBar/AppBarComponent.tsx @@ -1,4 +1,4 @@ -import { AppBar, Grid, Hidden, Toolbar } from "@mui/material"; +import { AppBar, Grid, Toolbar } from "@mui/material"; import { ReactElement, useEffect, useState } from "react"; import { useLocation } from "react-router-dom"; @@ -6,39 +6,37 @@ import { getProjectId } from "backend/localStorage"; import { getBasePath, Path } from "browserHistory"; import Logo from "components/AppBar/Logo"; import NavigationButtons from "components/AppBar/NavigationButtons"; -import ProjectNameButton from "components/AppBar/ProjectNameButton"; +import ProjectButtons from "components/AppBar/ProjectButtons"; import UserMenu from "components/AppBar/UserMenu"; import { topBarHeight } from "components/LandingPage/TopBar"; import DownloadButton from "components/ProjectExport/DownloadButton"; import theme from "types/theme"; +export const appBarHeight = 64; + /** An app bar shown at the top of all logged in pages */ export default function AppBarComponent(): ReactElement { const location = useLocation(); const [currentTab, setCurrentTab] = useState(Path.ProjScreen); + useEffect(() => setCurrentTab(getBasePath(location.pathname)), [location]); + return (
- + - - - - - + + + {!!getProjectId() && ( )} - - {!!getProjectId() && ( - - )} + + {!!getProjectId() && } diff --git a/src/components/AppBar/Logo.tsx b/src/components/AppBar/Logo.tsx index 8b762a7c0a..cfca5cf384 100644 --- a/src/components/AppBar/Logo.tsx +++ b/src/components/AppBar/Logo.tsx @@ -8,15 +8,19 @@ import smallLogo from "resources/CombineSmallLogoV1.png"; /** A button that redirects to the home page */ export default function Logo(): ReactElement { return ( - ); diff --git a/src/components/AppBar/NavigationButtons.tsx b/src/components/AppBar/NavigationButtons.tsx index 609af83036..4734afb7fc 100644 --- a/src/components/AppBar/NavigationButtons.tsx +++ b/src/components/AppBar/NavigationButtons.tsx @@ -1,89 +1,47 @@ import { Button } from "@mui/material"; -import React, { ReactElement, useState } from "react"; +import { ReactElement } from "react"; import { useTranslation } from "react-i18next"; -import { Permission } from "api"; -import * as backend from "backend"; -import * as LocalStorage from "backend/localStorage"; import history, { Path } from "browserHistory"; -import { openTreeAction } from "components/TreeView/TreeViewActions"; -import { useAppDispatch } from "types/hooks"; +import { appBarHeight } from "components/AppBar/AppBarComponent"; import { tabColor } from "types/theme"; interface NavigationButtonsProps { currentTab: Path; } -export async function getIsAdminOrOwner(): Promise { - const user = LocalStorage.getCurrentUser(); - if (user?.isAdmin) { - return true; - } else { - const projectId = LocalStorage.getProjectId(); - const userRoleID = user?.projectRoles[projectId]; - if (userRoleID) { - return backend.getUserRole(userRoleID).then((role) => { - return role.permissions.includes(Permission.Owner); - }); - } - } - return false; -} - /** A button that redirects to the home page */ export default function NavigationButtons( props: NavigationButtonsProps ): ReactElement { - const dispatch = useAppDispatch(); const { t } = useTranslation(); - const [isAdminOrOwner, setIsAdminOrOwner] = useState(false); - - getIsAdminOrOwner().then(setIsAdminOrOwner); return ( - + <> - {isAdminOrOwner && ( - - )} - + ); } diff --git a/src/components/AppBar/ProjectButtons.tsx b/src/components/AppBar/ProjectButtons.tsx new file mode 100644 index 0000000000..a1bb66cfb6 --- /dev/null +++ b/src/components/AppBar/ProjectButtons.tsx @@ -0,0 +1,85 @@ +import { BarChart, Settings } from "@mui/icons-material"; +import { Button, Hidden, Tooltip, Typography } from "@mui/material"; +import { ReactElement, useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { useSelector } from "react-redux"; + +import { Permission } from "api/models"; +import { getUserRole } from "backend"; +import { getCurrentUser, getProjectId } from "backend/localStorage"; +import history, { Path } from "browserHistory"; +import { StoreState } from "types"; +import { tabColor } from "types/theme"; + +interface ProjectButtonsProps { + currentTab: Path; +} + +export async function getIsAdminOrOwner(): Promise { + const user = getCurrentUser(); + if (!user) { + return false; + } + if (user.isAdmin) { + return true; + } + const userRoleID = user.projectRoles[getProjectId()]; + if (userRoleID) { + const role = await getUserRole(userRoleID); + return role.permissions.includes(Permission.Owner); + } + return false; +} + +/** A button that redirects to the project settings */ +export default function ProjectButtons( + props: ProjectButtonsProps +): ReactElement { + const projectName = useSelector( + (state: StoreState) => state.currentProjectState.project.name + ); + const [isAdminOrOwner, setIsAdminOrOwner] = useState(false); + const { t } = useTranslation(); + + useEffect(() => { + getIsAdminOrOwner().then(setIsAdminOrOwner); + }, [setIsAdminOrOwner]); + + return ( + <> + {isAdminOrOwner && ( + + + + )} + + + + + + {projectName} + + + + ); +} diff --git a/src/components/AppBar/ProjectNameButton.tsx b/src/components/AppBar/ProjectNameButton.tsx deleted file mode 100644 index 38d223f8fc..0000000000 --- a/src/components/AppBar/ProjectNameButton.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { Settings } from "@mui/icons-material"; -import { Button, Hidden, Tooltip } from "@mui/material"; -import { ReactElement } from "react"; -import { useTranslation } from "react-i18next"; -import { useSelector } from "react-redux"; - -import history, { Path } from "browserHistory"; -import { StoreState } from "types"; -import { tabColor } from "types/theme"; - -interface ProjectNameButtonProps { - currentTab: Path; -} - -/** A button that redirects to the project settings */ -export default function ProjectNameButton( - props: ProjectNameButtonProps -): ReactElement { - const projectName = useSelector( - (state: StoreState) => state.currentProjectState.project.name - ); - const { t } = useTranslation(); - - const background = tabColor(props.currentTab, Path.ProjSettings); - return ( - - - - ); -} diff --git a/src/components/AppBar/UserMenu.tsx b/src/components/AppBar/UserMenu.tsx index 64088c42c5..3a5cf38430 100644 --- a/src/components/AppBar/UserMenu.tsx +++ b/src/components/AppBar/UserMenu.tsx @@ -4,7 +4,14 @@ import { Person, SettingsApplications, } from "@mui/icons-material"; -import { Avatar, Button, Hidden, Menu, MenuItem } from "@mui/material"; +import { + Avatar, + Button, + Hidden, + Menu, + MenuItem, + Typography, +} from "@mui/material"; import React, { ReactElement, useState } from "react"; import { useTranslation } from "react-i18next"; @@ -50,16 +57,24 @@ export default function UserMenu(props: UserMenuProps): ReactElement { getIsAdmin().then(setIsAdmin); return ( - + <>