From 9288fa47578c455c90682e06281501a46b77ec1d Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Thu, 15 Jul 2021 09:47:24 +1000 Subject: [PATCH] Improvements to menus and suspense --- frontend/src/components/Dropdown/Dropdown.tsx | 4 ++- .../Navigation/NavigationHeader.tsx | 31 +++++++++++++++++-- .../components/Navigation/NavigationMenu.tsx | 20 ++++++++++-- frontend/src/components/Router.tsx | 8 ++--- frontend/src/components/SinglePage.tsx | 2 -- frontend/src/components/SuspenseLoader.tsx | 31 +++++++++++++++++++ frontend/src/components/index.ts | 2 ++ 7 files changed, 85 insertions(+), 13 deletions(-) create mode 100644 frontend/src/components/SuspenseLoader.tsx diff --git a/frontend/src/components/Dropdown/Dropdown.tsx b/frontend/src/components/Dropdown/Dropdown.tsx index 983471c7..9a73d8e3 100644 --- a/frontend/src/components/Dropdown/Dropdown.tsx +++ b/frontend/src/components/Dropdown/Dropdown.tsx @@ -37,6 +37,7 @@ export const Dropdown: React.FC = ({ arrow, dark, show, + ...rest }) => { return (
= ({ dark && ["bg-dark", "text-white"], show && "show", className, - )}> + )} + {...rest}> {header && {header}} {children}
diff --git a/frontend/src/components/Navigation/NavigationHeader.tsx b/frontend/src/components/Navigation/NavigationHeader.tsx index 49fb5b85..d593c60c 100644 --- a/frontend/src/components/Navigation/NavigationHeader.tsx +++ b/frontend/src/components/Navigation/NavigationHeader.tsx @@ -1,4 +1,4 @@ -import React, { ReactNode, useState } from "react"; +import React, { ReactNode, useState, useRef, useEffect } from "react"; import cn from "classnames"; import { Bell } from "tabler-icons-react"; @@ -75,6 +75,30 @@ export const NavigationHeader: React.FC = ({ }) => { const [notificationsShown, setNotificationsShown] = useState(false); const [profileShown, setProfileShown] = useState(false); + const profileRef = useRef(null); + const notificationsRef = useRef(null); + + const handleClickOutside = (event: any) => { + if ( + profileRef.current && + // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'. + !profileRef.current.contains(event.target) + ) { + setProfileShown(false); + } + if ( + notificationsRef.current && + // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'. + !notificationsRef.current.contains(event.target) + ) { + setNotificationsShown(false); + } + }; + + useEffect(() => { + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, []); return (
= ({ ) : null} {notifications ? ( -
+
) : null}
diff --git a/frontend/src/components/Navigation/NavigationMenu.tsx b/frontend/src/components/Navigation/NavigationMenu.tsx index f4145b74..382e6c44 100644 --- a/frontend/src/components/Navigation/NavigationMenu.tsx +++ b/frontend/src/components/Navigation/NavigationMenu.tsx @@ -1,4 +1,4 @@ -import React, { ReactNode, useState } from "react"; +import React, { ReactNode, useState, useRef, useEffect } from "react"; import cn from "classnames"; @@ -45,6 +45,22 @@ export const NavigationMenu: React.FC = ({ searchContent, }) => { const [dropdownShown, setDropdownShown] = useState(0); + const navRef = useRef(null); + + const handleClickOutside = (event: any) => { + if ( + navRef.current && + // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'. + !navRef.current.contains(event.target) + ) { + setDropdownShown(0); + } + }; + + useEffect(() => { + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, []); const itemClicked = ( e: React.MouseEvent, @@ -82,7 +98,7 @@ export const NavigationMenu: React.FC = ({ }; return wrapMenu( -
    +
      {items.map((item: any, idx: number) => { const onClickItem = ( e: React.MouseEvent, diff --git a/frontend/src/components/Router.tsx b/frontend/src/components/Router.tsx index 645beb66..a226ee13 100644 --- a/frontend/src/components/Router.tsx +++ b/frontend/src/components/Router.tsx @@ -1,6 +1,6 @@ import React, { lazy, Suspense } from "react"; -import { Loading, SiteWrapper, SinglePage } from "components"; +import { SiteWrapper, SuspenseLoader } from "components"; import { useAuthState, useHealthState, UserProvider } from "context"; import { BrowserRouter, Switch, Route } from "react-router-dom"; @@ -17,11 +17,7 @@ const Users = lazy(() => import("pages/Users")); function Router() { const { health } = useHealthState(); const { authenticated } = useAuthState(); - const Spinner = ( - - - - ); + const Spinner = ; if (health.loading) { return Spinner; diff --git a/frontend/src/components/SinglePage.tsx b/frontend/src/components/SinglePage.tsx index 09f89895..db60ce6a 100644 --- a/frontend/src/components/SinglePage.tsx +++ b/frontend/src/components/SinglePage.tsx @@ -1,6 +1,5 @@ import React, { ReactNode } from "react"; -import { Footer } from "components"; import styled from "styled-components"; const Root = styled.div` @@ -24,7 +23,6 @@ function SinglePage({ children }: Props) { return ( {children} -