Skip to content

Commit

Permalink
Merge pull request #47 from zimmerman-team/feat/auth
Browse files Browse the repository at this point in the history
Authentication & Authorisation
  • Loading branch information
stephanoshadjipetrou authored Oct 24, 2023
2 parents 56d0db4 + 65cb0db commit bed827b
Show file tree
Hide file tree
Showing 47 changed files with 1,449 additions and 548 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"url": "https://github.com/zimmerman-team/dx.client.git"
},
"dependencies": {
"@auth0/auth0-react": "^2.2.1",
"@craco/craco": "^6.4.3",
"@devhammed/use-cookie": "^1.1.1",
"@draft-js-plugins/anchor": "^4.1.4",
Expand Down Expand Up @@ -162,7 +163,7 @@
"initialise": "yarn link '@rawgraphs/rawgraphs-charts' && yarn install --network-timeout 100000",
"docker-staging": "cp -r /app/client/build /app/client/staging && tail -f /dev/null",
"docker-test": "cp -r /app/client/build /app/client/test && tail -f /dev/null",
"docker-prod": "cp -r /app/client/build /app/client/prod"
"docker-prod": "cp -r /app/client/build /app/client/prod && tail -f /dev/null"
},
"browserslist": {
"production": [
Expand Down
144 changes: 103 additions & 41 deletions src/app/Routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,18 @@

// base
import React, { Suspense, lazy } from "react";
import { Switch } from "react-router-dom";
import { useScrollToTop } from "app/hooks/useScrollToTop";
import { PageLoader } from "app/modules/common/page-loader";
import { RouteWithAppBar } from "app/utils/RouteWithAppBar";
import { Route, Switch, useHistory } from "react-router-dom";
import { NoMatchPage } from "app/modules/common/no-match-page";
import {
AppState,
Auth0Provider,
User,
WithAuthenticationRequiredOptions,
withAuthenticationRequired,
} from "@auth0/auth0-react";

const HomeModule = lazy(() => import("app/modules/home-module"));
const CasesModule = lazy(
Expand All @@ -15,7 +22,6 @@ const CasesModule = lazy(
const ContactModule = lazy(
() => import("app/modules/home-module/sub-modules/contact")
);

const AboutModule = lazy(
() => import("app/modules/home-module/sub-modules/about")
);
Expand All @@ -25,8 +31,6 @@ const WhyDXModule = lazy(
const ExploreAssetsModule = lazy(
() => import("app/modules/home-module/sub-modules/explore-assets")
);
const DatasetsModule = lazy(() => import("app/modules/datasets-module"));
const ChartsModule = lazy(() => import("app/modules/charts-module"));
const ChartModule = lazy(() => import("app/modules/chart-module"));
const ReportModule = lazy(() => import("app/modules/report-module"));
const DatasetUploadSteps = lazy(
Expand All @@ -35,47 +39,105 @@ const DatasetUploadSteps = lazy(
const EditMetaData = lazy(
() => import("app/modules/datasets-module/editMetaData")
);
const AuthCallbackModule = lazy(() => import("app/modules/callback-module"));
const OnboardingModule = lazy(() => import("app/modules/onboarding-module"));
const UserProfileModule = lazy(() => import("app/modules/user-profile-module"));

const ProtectedRoute = (props: {
component: React.ComponentType<any>;
args?: WithAuthenticationRequiredOptions;
}) => {
const Component = withAuthenticationRequired(props.component, props.args);

return <Component />;
};

const Auth0ProviderWithRedirectCallback = (props: {
domain: string;
clientId: string;
authorizationParams: {
audience: string;
redirect_uri: string;
};
children: React.ReactNode;
}) => {
const history = useHistory();

const onRedirectCallback = (appState?: AppState, user?: User) => {
history.push(
appState && appState.returnTo
? appState.returnTo
: window.location.pathname
);
};

return (
<Auth0Provider onRedirectCallback={onRedirectCallback} {...props}>
{props.children}
</Auth0Provider>
);
};

export function MainRoutes() {
useScrollToTop();

return (
<Suspense fallback={<PageLoader />}>
<Switch>
<RouteWithAppBar exact path="/">
<HomeModule />
</RouteWithAppBar>
<RouteWithAppBar exact path="/cases">
<CasesModule />
</RouteWithAppBar>
<RouteWithAppBar exact path="/contact">
<ContactModule />
</RouteWithAppBar>
<RouteWithAppBar exact path="/why-dx">
<WhyDXModule />
</RouteWithAppBar>
<RouteWithAppBar exact path="/explore-assets">
<ExploreAssetsModule />
</RouteWithAppBar>
<RouteWithAppBar exact path="/report/:page/:view?">
<ReportModule />
</RouteWithAppBar>
<RouteWithAppBar exact path="/about">
<AboutModule />
</RouteWithAppBar>
<RouteWithAppBar exact path="/chart/:page/:view?">
<ChartModule />
</RouteWithAppBar>
<RouteWithAppBar exact path="/dataset/:id/edit">
<EditMetaData />
</RouteWithAppBar>
<RouteWithAppBar exact path="/dataset-upload">
<DatasetUploadSteps />
</RouteWithAppBar>
<RouteWithAppBar path="*">
<NoMatchPage />
</RouteWithAppBar>
</Switch>
</Suspense>
<Auth0ProviderWithRedirectCallback
domain={process.env.REACT_APP_AUTH0_DOMAIN!}
clientId={process.env.REACT_APP_AUTH0_CLIENT!}
authorizationParams={{
audience: process.env.REACT_APP_AUTH0_AUDIENCE!,
redirect_uri: `${window.location.origin}/callback`,
}}
>
<Suspense fallback={<PageLoader />}>
<Switch>
<Route exact path="/callback">
<AuthCallbackModule />
</Route>
<RouteWithAppBar exact path="/">
<HomeModule />
</RouteWithAppBar>
<RouteWithAppBar exact path="/cases">
<CasesModule />
</RouteWithAppBar>
<RouteWithAppBar exact path="/contact">
<ContactModule />
</RouteWithAppBar>
<RouteWithAppBar exact path="/why-dx">
<WhyDXModule />
</RouteWithAppBar>
<RouteWithAppBar exact path="/explore-assets">
<ExploreAssetsModule />
</RouteWithAppBar>
<RouteWithAppBar exact path="/report/:page/:view?">
<ReportModule />
</RouteWithAppBar>
<RouteWithAppBar exact path="/about">
<AboutModule />
</RouteWithAppBar>
<RouteWithAppBar exact path="/chart/:page/:view?">
<ChartModule />
</RouteWithAppBar>
<RouteWithAppBar exact path="/dataset/:id/edit">
<EditMetaData />
</RouteWithAppBar>
<RouteWithAppBar exact path="/dataset-upload">
<DatasetUploadSteps />
</RouteWithAppBar>
<RouteWithAppBar path="/onboarding">
<OnboardingModule />
</RouteWithAppBar>
<RouteWithAppBar
exact
path="/profile"
element={<ProtectedRoute component={UserProfileModule} />}
/>
<RouteWithAppBar path="*">
<NoMatchPage />
</RouteWithAppBar>
</Switch>
</Suspense>
</Auth0ProviderWithRedirectCallback>
);
}
82 changes: 51 additions & 31 deletions src/app/components/AppBar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
import React from "react";
import get from "lodash/get";
import { useRecoilState } from "recoil";
import Grid from "@material-ui/core/Grid";
import { useAuth0 } from "@auth0/auth0-react";
import Popover from "@material-ui/core/Popover";
import Toolbar from "@material-ui/core/Toolbar";
import MUIAppBar from "@material-ui/core/AppBar";
import MenuItem from "@material-ui/core/MenuItem";
import { useCMSData } from "app/hooks/useCMSData";
import Container from "@material-ui/core/Container";
import IconButton from "@material-ui/core/IconButton";
import KeyboardArrowDownIcon from "@material-ui/icons/KeyboardArrowDown";
import { withStyles } from "@material-ui/core/styles";
import { homeDisplayAtom } from "app/state/recoil/atoms";
import Menu, { MenuProps } from "@material-ui/core/Menu";
import useMediaQuery from "@material-ui/core/useMediaQuery";
import IconChevronLeft from "@material-ui/icons/ChevronLeft";
import { MobileAppbarSearch } from "app/components/Mobile/AppBarSearch";
import KeyboardArrowDownIcon from "@material-ui/icons/KeyboardArrowDown";
import { NavLink, useLocation, useHistory, Link } from "react-router-dom";
import {
headercss,
loginBtn,
logocss,
navLinkcss,
} from "app/components/AppBar/style";
import { MobileAppbarSearch } from "app/components/Mobile/AppBarSearch";
import { NavLink, useLocation, useHistory, Link } from "react-router-dom";
import { Grid, Popover } from "@material-ui/core";

const TextHeader = (label: string) => (
<h2
Expand Down Expand Up @@ -113,9 +113,10 @@ export function AppBar() {
const cmsData = useCMSData({ returnData: true });
const isMobile = useMediaQuery("(max-width: 767px)");
const [openSearch, setOpenSearch] = React.useState(false);
const [display, setDisplay] = useRecoilState(homeDisplayAtom);
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);

const navLocation = location.pathname.split("/").join("");

function handleClick(event: React.MouseEvent<HTMLElement>) {
setAnchorEl(event.currentTarget);
}
Expand Down Expand Up @@ -152,9 +153,6 @@ export function AppBar() {
if (location.pathname === "/" && isMobile) {
return <React.Fragment />;
}
const handlePath = (path: "charts" | "reports" | "data") => {
setDisplay(path);
};

return (
<MUIAppBar
Expand Down Expand Up @@ -217,21 +215,20 @@ export function AppBar() {
/>
</NavLink>
</Grid>

<Grid
item
lg={9}
md={10}
sm={10}
css={`
gap: 20px;
display: flex;
align-items: center;
justify-content: flex-end;
gap: 20px;
`}
>
<div css={navLinkcss("why-dx", navLocation)}>
<NavLink to="/why-dx" onClick={() => handlePath("data")}>
<NavLink to="/why-dx">
<b>Why Dx?</b>
</NavLink>
</div>
Expand All @@ -240,19 +237,18 @@ export function AppBar() {
<b>Explore Assets</b>
</NavLink>
</div>

<div css={navLinkcss("about", navLocation)}>
<Link to="/about" onClick={() => handlePath("reports")}>
<Link to="/about">
<b>About</b>
</Link>
</div>
<div css={navLinkcss("cases", navLocation)}>
<Link to="/cases" onClick={() => handlePath("reports")}>
<Link to="/cases">
<b>Cases </b>
</Link>
</div>
<div css={navLinkcss("contact", navLocation)}>
<Link to="/contact" onClick={() => handlePath("reports")}>
<Link to="/contact">
<b>Contact </b>
</Link>
</div>
Expand All @@ -267,6 +263,9 @@ export function AppBar() {
}

const ActionMenu = () => {
const history = useHistory();
const { user, isAuthenticated } = useAuth0();

const [actionPopoverAnchorEl, setActionPopoverAnchorEl] =
React.useState<HTMLButtonElement | null>(null);

Expand All @@ -280,10 +279,9 @@ const ActionMenu = () => {
<div>
<div
css={`
display: flex;
gap: 1px;
display: flex;
position: relative;
width: 188px;
button {
outline: none;
Expand All @@ -298,7 +296,7 @@ const ActionMenu = () => {
:nth-child(1) {
width: 146px;
height: 34px;
border-radius: 24px 0px 0px 24px;
border-radius: ${isAuthenticated ? "24px 0px 0px 24px" : "24px"};
&:hover {
opacity: 1;
}
Expand All @@ -318,18 +316,40 @@ const ActionMenu = () => {
}
`}
>
<Link to="/report/new/initial">
<button>Create report</button>
</Link>
<button
onClick={(event: React.MouseEvent<HTMLButtonElement>) => {
setActionPopoverAnchorEl(
actionPopoverAnchorEl ? null : event.currentTarget
);
}}
<Link
to={isAuthenticated ? "/report/new/initial" : "/onboarding/login"}
>
<KeyboardArrowDownIcon />
</button>
<button>{isAuthenticated ? "Create report" : "Login"}</button>
</Link>
{isAuthenticated && (
<button
onClick={(event: React.MouseEvent<HTMLButtonElement>) => {
setActionPopoverAnchorEl(
actionPopoverAnchorEl ? null : event.currentTarget
);
}}
>
<KeyboardArrowDownIcon />
</button>
)}
{isAuthenticated && (
<button
onClick={() => history.push("/profile")}
css={`
min-width: 33px;
height: 33px;
display: flex;
margin-left: 20px;
border-radius: 50%;
align-items: center;
background: #b5b5db;
justify-content: center;
`}
>
{user?.given_name?.slice(0, 1)}
{user?.family_name?.slice(0, 1)}
</button>
)}
</div>
<Popover
open={openActionPopover}
Expand Down
3 changes: 2 additions & 1 deletion src/app/components/Dialogs/CookieDialog/common/message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ export const Message = (props: MessageProps) => {
<MessageContainer display="flex">
<Typo
variant="body1"
color="#231D2C"
css={`
color: #231d2c;
a {
color: #231d2c;
}
Expand Down
Loading

0 comments on commit bed827b

Please sign in to comment.