Skip to content

Commit 9288fa4

Browse files
committed
Improvements to menus and suspense
1 parent 52f3801 commit 9288fa4

File tree

7 files changed

+85
-13
lines changed

7 files changed

+85
-13
lines changed

frontend/src/components/Dropdown/Dropdown.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export const Dropdown: React.FC<DropdownProps> = ({
3737
arrow,
3838
dark,
3939
show,
40+
...rest
4041
}) => {
4142
return (
4243
<div
@@ -46,7 +47,8 @@ export const Dropdown: React.FC<DropdownProps> = ({
4647
dark && ["bg-dark", "text-white"],
4748
show && "show",
4849
className,
49-
)}>
50+
)}
51+
{...rest}>
5052
{header && <span className="dropdown-header">{header}</span>}
5153
{children}
5254
</div>

frontend/src/components/Navigation/NavigationHeader.tsx

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { ReactNode, useState } from "react";
1+
import React, { ReactNode, useState, useRef, useEffect } from "react";
22

33
import cn from "classnames";
44
import { Bell } from "tabler-icons-react";
@@ -75,6 +75,30 @@ export const NavigationHeader: React.FC<NavigationHeaderProps> = ({
7575
}) => {
7676
const [notificationsShown, setNotificationsShown] = useState(false);
7777
const [profileShown, setProfileShown] = useState(false);
78+
const profileRef = useRef(null);
79+
const notificationsRef = useRef(null);
80+
81+
const handleClickOutside = (event: any) => {
82+
if (
83+
profileRef.current &&
84+
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
85+
!profileRef.current.contains(event.target)
86+
) {
87+
setProfileShown(false);
88+
}
89+
if (
90+
notificationsRef.current &&
91+
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
92+
!notificationsRef.current.contains(event.target)
93+
) {
94+
setNotificationsShown(false);
95+
}
96+
};
97+
98+
useEffect(() => {
99+
document.addEventListener("mousedown", handleClickOutside);
100+
return () => document.removeEventListener("mousedown", handleClickOutside);
101+
}, []);
78102

79103
return (
80104
<header
@@ -100,7 +124,9 @@ export const NavigationHeader: React.FC<NavigationHeaderProps> = ({
100124
</div>
101125
) : null}
102126
{notifications ? (
103-
<div className="nav-item dropdown d-none d-md-flex me-3">
127+
<div
128+
className="nav-item dropdown d-none d-md-flex me-3"
129+
ref={notificationsRef}>
104130
<button
105131
style={{
106132
border: 0,
@@ -125,6 +151,7 @@ export const NavigationHeader: React.FC<NavigationHeaderProps> = ({
125151
</div>
126152
) : null}
127153
<div
154+
ref={profileRef}
128155
className={cn("nav-item", {
129156
dropdown: !!profileItems,
130157
})}>

frontend/src/components/Navigation/NavigationMenu.tsx

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { ReactNode, useState } from "react";
1+
import React, { ReactNode, useState, useRef, useEffect } from "react";
22

33
import cn from "classnames";
44

@@ -45,6 +45,22 @@ export const NavigationMenu: React.FC<NavigationMenuProps> = ({
4545
searchContent,
4646
}) => {
4747
const [dropdownShown, setDropdownShown] = useState(0);
48+
const navRef = useRef(null);
49+
50+
const handleClickOutside = (event: any) => {
51+
if (
52+
navRef.current &&
53+
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
54+
!navRef.current.contains(event.target)
55+
) {
56+
setDropdownShown(0);
57+
}
58+
};
59+
60+
useEffect(() => {
61+
document.addEventListener("mousedown", handleClickOutside);
62+
return () => document.removeEventListener("mousedown", handleClickOutside);
63+
}, []);
4864

4965
const itemClicked = (
5066
e: React.MouseEvent<HTMLAnchorElement, MouseEvent>,
@@ -82,7 +98,7 @@ export const NavigationMenu: React.FC<NavigationMenuProps> = ({
8298
};
8399

84100
return wrapMenu(
85-
<ul className="navbar-nav">
101+
<ul className="navbar-nav" ref={navRef}>
86102
{items.map((item: any, idx: number) => {
87103
const onClickItem = (
88104
e: React.MouseEvent<HTMLAnchorElement, MouseEvent>,

frontend/src/components/Router.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { lazy, Suspense } from "react";
22

3-
import { Loading, SiteWrapper, SinglePage } from "components";
3+
import { SiteWrapper, SuspenseLoader } from "components";
44
import { useAuthState, useHealthState, UserProvider } from "context";
55
import { BrowserRouter, Switch, Route } from "react-router-dom";
66

@@ -17,11 +17,7 @@ const Users = lazy(() => import("pages/Users"));
1717
function Router() {
1818
const { health } = useHealthState();
1919
const { authenticated } = useAuthState();
20-
const Spinner = (
21-
<SinglePage>
22-
<Loading />
23-
</SinglePage>
24-
);
20+
const Spinner = <SuspenseLoader />;
2521

2622
if (health.loading) {
2723
return Spinner;

frontend/src/components/SinglePage.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import React, { ReactNode } from "react";
22

3-
import { Footer } from "components";
43
import styled from "styled-components";
54

65
const Root = styled.div`
@@ -24,7 +23,6 @@ function SinglePage({ children }: Props) {
2423
return (
2524
<Root>
2625
<Wrapper>{children}</Wrapper>
27-
<Footer />
2826
</Root>
2927
);
3028
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React from "react";
2+
3+
import { Loading } from "components";
4+
import styled from "styled-components";
5+
6+
const Root = styled.div`
7+
display: flex;
8+
flex-direction: column;
9+
justify-content: center;
10+
min-height: 100%;
11+
`;
12+
13+
const Wrapper = styled.div`
14+
flex: 1 1 auto;
15+
display: flex;
16+
align-items: center;
17+
justify-content: center;
18+
min-height: 100px;
19+
`;
20+
21+
function SuspenseLoader() {
22+
return (
23+
<Root>
24+
<Wrapper>
25+
<Loading />
26+
</Wrapper>
27+
</Root>
28+
);
29+
}
30+
31+
export { SuspenseLoader };

frontend/src/components/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ export * from "./Footer";
99
export * from "./Loader";
1010
export * from "./Loading";
1111
export * from "./Navigation";
12+
export * from "./NavMenu";
1213
export * from "./Router";
1314
export * from "./SinglePage";
1415
export * from "./SiteWrapper";
16+
export * from "./SuspenseLoader";
1517
export * from "./Unhealthy";

0 commit comments

Comments
 (0)