diff --git a/react/src/assets/Hazmapper-Stack@4x.png b/react/src/assets/Hazmapper-Stack@4x.png new file mode 100644 index 00000000..1158063b Binary files /dev/null and b/react/src/assets/Hazmapper-Stack@4x.png differ diff --git a/react/src/assets/designsafe.svg b/react/src/assets/designsafe.svg new file mode 100644 index 00000000..48f4fee6 --- /dev/null +++ b/react/src/assets/designsafe.svg @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/react/src/assets/hazmapper-header-logo.png b/react/src/assets/hazmapper-header-logo.png new file mode 100644 index 00000000..71fed6be Binary files /dev/null and b/react/src/assets/hazmapper-header-logo.png differ diff --git a/react/src/assets/nheri.png b/react/src/assets/nheri.png new file mode 100644 index 00000000..26e82495 Binary files /dev/null and b/react/src/assets/nheri.png differ diff --git a/react/src/assets/nsf.png b/react/src/assets/nsf.png new file mode 100644 index 00000000..7c52c695 Binary files /dev/null and b/react/src/assets/nsf.png differ diff --git a/react/src/components/HeaderNavBar/HeaderNavBar.module.css b/react/src/components/HeaderNavBar/HeaderNavBar.module.css new file mode 100644 index 00000000..d18d3fab --- /dev/null +++ b/react/src/components/HeaderNavBar/HeaderNavBar.module.css @@ -0,0 +1,10 @@ +.root { + display: flex; + align-items: center; + flex-direction: row; + justify-content: space-between; + height: var(--hazmapper-header-navbar-height); +} +.userName { + color: white; +} diff --git a/react/src/components/HeaderNavBar/HeaderNavBar.tsx b/react/src/components/HeaderNavBar/HeaderNavBar.tsx new file mode 100644 index 00000000..93b90a39 --- /dev/null +++ b/react/src/components/HeaderNavBar/HeaderNavBar.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import { Layout } from 'antd'; +import useAuthenticatedUser from '@hazmapper/hooks/user/useAuthenticatedUser'; +import { useNavigate } from 'react-router-dom'; +import { Button, InlineMessage, LoadingSpinner } from '@tacc/core-components'; +import styles from './HeaderNavBar.module.css'; + +export const HeaderNavBar: React.FC = () => { + const { Header } = Layout; + const navigate = useNavigate(); + + const { + data: userData, + isLoading: isUserLoading, + error: isUserError, + } = useAuthenticatedUser(); + + const handleLogin = () => { + const url = `/login?to=${encodeURIComponent(location.pathname)}`; + navigate(url); + }; + + if (isUserLoading) { + return ; + } + + if (isUserError) { + return ( + + {' '} + There was an error loading your username. + + ); + } + + return ( +
+ Hazmapper Logo + {userData && userData.username ? ( +
{userData.username}
+ ) : ( + + )} +
+ ); +}; +export default HeaderNavBar; diff --git a/react/src/components/HeaderNavBar/index.tsx b/react/src/components/HeaderNavBar/index.tsx new file mode 100644 index 00000000..cafd8fc5 --- /dev/null +++ b/react/src/components/HeaderNavBar/index.tsx @@ -0,0 +1 @@ +export { default } from './HeaderNavBar'; diff --git a/react/src/components/Projects/ProjectListing.module.css b/react/src/components/Projects/ProjectListing.module.css index 554d5860..f4c7da22 100644 --- a/react/src/components/Projects/ProjectListing.module.css +++ b/react/src/components/Projects/ProjectListing.module.css @@ -1,50 +1,90 @@ .root { display: flex; + flex-direction: column; + padding-left: 50px; + padding-right: 50px; +} +.errorMessage { width: 100%; + padding: 10px; } +.errorMessage p { + justify-content: center; +} + .projectList { - width: 100%; - table-layout: fixed; + flex-grow: 1; + overflow: hidden; + justify-content: center; padding: 10px; } -.errorMessage { + +.projectList table { width: 100%; - padding: 10px; + table-layout: fixed; + border-collapse: collapse; } -.projectList th { + +.projectList thead { + position: sticky; + top: 0; + z-index: 10; background: #d0d0d0; +} + +.projectList thead th { text-overflow: ellipsis; overflow: hidden; white-space: nowrap; + background: #d0d0d0; +} + +.projectList tbody { + display: block; + max-height: 300px; + overflow-y: auto; } -.projectList tr, -td { + +.projectList tr { + display: table; width: 100%; + table-layout: fixed; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; } + .projectList tr:hover td { color: white; background-color: var(--global-color-accent--light); } + .projectList tr:hover td button { color: white; } + .mapColumn { width: 42%; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; } + .projectColumn { width: 42%; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; } + .buttonColumn { width: 16%; text-align: end; } + .buttonColumn button { max-width: 100%; text-overflow: ellipsis; - overflow: hidden; white-space: nowrap; justify-content: flex-start; } diff --git a/react/src/components/Projects/ProjectListing.tsx b/react/src/components/Projects/ProjectListing.tsx index a99d5171..e8d3c2cd 100644 --- a/react/src/components/Projects/ProjectListing.tsx +++ b/react/src/components/Projects/ProjectListing.tsx @@ -26,7 +26,11 @@ const ProjectListing: React.FC = () => { useProjectsWithDesignSafeInformation(); if (isLoading) { - return ; + return ( +
+ +
+ ); } if (isError) { @@ -52,54 +56,59 @@ const ProjectListing: React.FC = () => { return (
- - - - - - - - - - {data && data?.length > 0 ? ( - data.map((proj) => ( - navigateToProject(proj.uuid)}> - - + + + )) + ) : ( + + )} + +
MapProject - - -
{proj.name} - {proj.ds_project - ? `${proj.ds_project?.value.projectId} | +
+ + + + + + + + + + {data && data?.length > 0 ? ( + data.map((proj) => ( + navigateToProject(proj.uuid)}> + + - - - )) - ) : ( - - )} - -
MapProject + + +
{proj.name} + {proj.ds_project + ? `${proj.ds_project?.value.projectId} | ${proj.ds_project?.value.title}` - : '---------'} - - - -
- - No maps found. -
- {' '} - to get started. -
-
+ : '---------'} +
+ + +
+ + No maps found. +
+ {' '} + to get started. +
+
+
{selectedProjectForDeletion && ( { // Wait for the "Main Menu" text to be rendered and then check it await waitFor(() => { - expect(getByText(/Main Menu/)).toBeDefined(); + expect(getByText(/mockUser/)).toBeDefined(); }); }); diff --git a/react/src/pages/MainMenu/MainMenu.tsx b/react/src/pages/MainMenu/MainMenu.tsx index e9b50e6c..7e06f44f 100644 --- a/react/src/pages/MainMenu/MainMenu.tsx +++ b/react/src/pages/MainMenu/MainMenu.tsx @@ -1,54 +1,75 @@ -import React, { useState } from 'react'; -import { - LoadingSpinner, - InlineMessage, - SectionHeader, - Icon, -} from '@tacc/core-components'; -import useAuthenticatedUser from '@hazmapper/hooks/user/useAuthenticatedUser'; -import { SystemSelect } from '@hazmapper/components/Systems'; +import React from 'react'; import ProjectListing from '@hazmapper/components/Projects/ProjectListing'; +import styles from './layout.module.css'; +import { Button } from '@tacc/core-components'; +import HeaderNavBar from '@hazmapper/components/HeaderNavBar'; const MainMenu = () => { - const { - data: userData, - isLoading: isUserLoading, - error: userError, - } = useAuthenticatedUser(); - - const [selectedSystem, setSelectedSystem] = useState(''); - - if (isUserLoading) { - return ( - <> - Main Menu - - - ); - } - if (userError) { - <> - Main Menu - Unable to retrieve projects. - ; - } - - const handleSelectChange = (system: string) => { - setSelectedSystem(system); - }; - return ( - <> - Main Menu -
- - Welcome, {userData?.username || 'User'} - +
+ +
+
+ Hazmapper Logo +
{'Version 2.17'}
+
+ + + +
+ - - {selectedSystem &&
Current system selected: {selectedSystem}
} - - +
); }; diff --git a/react/src/pages/MainMenu/layout.module.css b/react/src/pages/MainMenu/layout.module.css new file mode 100644 index 00000000..6d7aafae --- /dev/null +++ b/react/src/pages/MainMenu/layout.module.css @@ -0,0 +1,39 @@ +.root { + display: flex; + flex-direction: column; + min-height: 100vh; + min-width: 100%; +} +.listingContainer { + flex-grow: 1; +} +.versionContainer { + display: flex; + flex-direction: column; + width: 100%; + justify-content: center; + align-items: center; +} +.versionContainer img { + width: 250px; +} +.sponsorContainer { + display: flex; + justify-content: center; + width: 100%; + height: 100%; + align-items: center; + position: sticky; + background-color: #f7f7f7; +} +.sponsorContainer img { + padding: 10px; + object-fit: contain; +} +.userGuide { + width: 100%; + justify-content: right; + font-weight: bold; + font-size: medium; + padding-right: 50px; +} diff --git a/react/src/pages/MapProject/MapProject.module.css b/react/src/pages/MapProject/MapProject.module.css index 4abfc5a5..19d843c8 100644 --- a/react/src/pages/MapProject/MapProject.module.css +++ b/react/src/pages/MapProject/MapProject.module.css @@ -16,8 +16,8 @@ .topNavbar { background-color: black; color: white; - height: var(--hazmapper-top-navbar-height); - min-height: var(--hazmapper-top-navbar-height); + height: var(--hazmapper-header-navbar-height); + min-height: var(--hazmapper-header-navbar-height); display: flex; align-items: center; } @@ -33,7 +33,7 @@ .container { height: calc( - 100vh - var(--hazmapper-top-navbar-height) - + 100vh - var(--hazmapper-header-navbar-height) - var(--hazmapper-control-bar-height) ); width: 100%; @@ -44,7 +44,7 @@ .panelContainer { width: var(--hazmapper-panel-width); height: calc( - 100vh - var(--hazmapper-top-navbar-height) - + 100vh - var(--hazmapper-header-navbar-height) - var(--hazmapper-control-bar-height) ); background-color: var(--global-color-primary--xx-light); diff --git a/react/src/pages/MapProject/MapProject.tsx b/react/src/pages/MapProject/MapProject.tsx index 5220149c..455865c8 100644 --- a/react/src/pages/MapProject/MapProject.tsx +++ b/react/src/pages/MapProject/MapProject.tsx @@ -13,6 +13,7 @@ import Filters from '@hazmapper/components/FiltersPanel/Filter'; import { assetTypeOptions } from '@hazmapper/components/FiltersPanel/Filter'; import { Project } from '@hazmapper/types'; import { Message, LoadingSpinner } from '@tacc/core-components'; +import HeaderNavBar from '@hazmapper/components/HeaderNavBar'; interface MapProjectProps { /** @@ -151,7 +152,7 @@ const LoadedMapProject: React.FC = ({ return (
-
MapTopNavBar
+
MapTopControlBar {loading &&
loading
} diff --git a/react/src/redux/authSlice.ts b/react/src/redux/authSlice.ts index 9988eec3..6bd2dc3c 100644 --- a/react/src/redux/authSlice.ts +++ b/react/src/redux/authSlice.ts @@ -17,10 +17,8 @@ const authSlice = createSlice({ state, action: PayloadAction<{ user: AuthenticatedUser; authToken: AuthToken }> ) { - state = { - user: action.payload.user, - authToken: action.payload.authToken, - }; + state.user = action.payload.user; + state.authToken = action.payload.authToken; // save to local storage setAuthenticatedUserFromLocalStorage(state);