Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(refactor-ui): Refactor and Improve Auth Flows within UI #55

Merged
merged 17 commits into from
Jul 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 23 additions & 19 deletions src/services/ui/index.html
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
<!DOCTYPE html>
<html lang="en">
<html lang="en" class="h-full">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;500;600;700&display=swap"
rel="stylesheet"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>CMS OM Template</title>
</head>

<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>CMS OM Template</title>
</head>

<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
<script>
if (global === undefined) {
var global = window;
}
</script>
</body>

</html>
<body class="h-full">
<div id="root" class="h-full"></div>
<script type="module" src="/src/main.tsx"></script>
<script>
if (global === undefined) {
var global = window;
}
</script>
</body>
</html>
1 change: 1 addition & 0 deletions src/services/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"@playwright/test": "^1.34.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@types/node": "^20.4.2",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@typescript-eslint/eslint-plugin": "^5.59.0",
Expand Down
28 changes: 28 additions & 0 deletions src/services/ui/src/api/amplifyConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Amplify } from "aws-amplify";
import config from "@/config";

Amplify.configure({
Auth: {
mandatorySignIn: true,
region: config.cognito.REGION,
userPoolId: config.cognito.USER_POOL_ID,
identityPoolId: config.cognito.IDENTITY_POOL_ID,
userPoolWebClientId: config.cognito.APP_CLIENT_ID,
oauth: {
domain: config.cognito.APP_CLIENT_DOMAIN,
redirectSignIn: config.cognito.REDIRECT_SIGNIN,
redirectSignOut: config.cognito.REDIRECT_SIGNOUT,
scope: ["email", "openid"],
responseType: "code",
},
},
API: {
endpoints: [
{
name: "seatool",
endpoint: config.apiGateway.URL,
region: config.apiGateway.REGION,
},
],
},
});
27 changes: 27 additions & 0 deletions src/services/ui/src/api/useGetUser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import "@/api/amplifyConfig";
import { getParsedObject } from "@/utils";
import { useQuery } from "@tanstack/react-query";
import { Auth } from "aws-amplify";
import { CognitoUserAttributes } from "shared-types";

export const getUser = async () => {
try {
const authenticatedUser = await Auth.currentAuthenticatedUser();
const attributes = await Auth.userAttributes(authenticatedUser);
const user = attributes.reduce((obj: { [key: string]: string }, item) => {
obj[item.Name] = item.Value;
return obj;
}, {});

return { user: getParsedObject(user) as CognitoUserAttributes };
} catch (e) {
console.log({ e });
return { user: null };
}
};

export const useGetUser = () =>
useQuery({
queryKey: ["user"],
queryFn: () => getUser(),
});
9 changes: 9 additions & 0 deletions src/services/ui/src/assets/onemac_logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions src/services/ui/src/components/HowItWorks/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export const HowItWorks = ({ children }: React.PropsWithChildren) => {
return (
<div className="py-8 px-6 border border-gray-300 rounded-md border-solid w-full">
<h4 className="text-bold text-xl">How it works</h4>
{children}
</div>
);
};

export type StepProps = {
icon: React.ReactNode;
title: React.ReactNode;
content: React.ReactNode;
};

export const Step = ({ icon, content, title }: StepProps) => {
return (
<div className="flex gap-4 items-center mt-4">
{icon}
<div className="">
<p className="text-bold">{title}</p>
<p className="">{content}</p>
</div>
</div>
);
};
176 changes: 176 additions & 0 deletions src/services/ui/src/components/Layout/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import { Link, NavLink, NavLinkProps, Outlet } from "react-router-dom";
import * as UI from "@enterprise-cmcs/macpro-ux-lib";
import oneMacLogo from "@/assets/onemac_logo.svg";
import { useMediaQuery } from "@/hooks";
import { Bars3Icon, XMarkIcon } from "@heroicons/react/24/outline";
import { useState } from "react";
import { useGetUser } from "@/api/useGetUser";
import { Auth } from "aws-amplify";
import { AwsCognitoOAuthOpts } from "@aws-amplify/auth/lib-esm/types";

const getLinks = (isAuthenticated: boolean) => {
if (isAuthenticated) {
return [
{
name: "Home",
link: "/",
},
{
name: "Dashboard",
link: "/dashboard",
},
];
} else {
return [
{
name: "Home",
link: "/",
},
];
}
};

export const Layout = () => {
const isDesktop = useMediaQuery("(min-width: 768px)");

return (
<div className="min-h-full flex flex-col">
<UI.UsaBanner />
<div className="bg-primary">
<div className="max-w-screen-lg mx-auto px-4 lg:px-8">
<div className="h-[70px] flex gap-12 items-center text-white">
<Link to="/">
<img
className="h-10 w-28 min-w-[112px] resize-none"
src={oneMacLogo}
alt="One Mac Site Logo"
/>
</Link>
<ResponsiveNav isDesktop={isDesktop} />
</div>
</div>
</div>
<main className="flex-1">
<Outlet />
</main>
<UI.Footer emailAddress="[email protected]" />
</div>
);
};

type ResponsiveNavProps = {
isDesktop: boolean;
};
const ResponsiveNav = ({ isDesktop }: ResponsiveNavProps) => {
const [prevMediaQuery, setPrevMediaQuery] = useState(isDesktop);
const [isOpen, setIsOpen] = useState(false);
const { isLoading, isError, data } = useGetUser();

const handleLogin = () => {
const authConfig = Auth.configure();
const { domain, redirectSignIn, responseType } =
authConfig.oauth as AwsCognitoOAuthOpts;
const clientId = authConfig.userPoolWebClientId;
const url = `https://${domain}/oauth2/authorize?redirect_uri=${redirectSignIn}&response_type=${responseType}&client_id=${clientId}`;

window.location.assign(url);
};

const handleLogout = async () => {
await Auth.signOut();
};

if (isLoading || isError) return <></>;

const setClassBasedOnNav: NavLinkProps["className"] = ({ isActive }) =>
isActive
? "underline underline-offset-4 decoration-4 hover:text-white/70"
: "hover:text-white/70";

if (prevMediaQuery !== isDesktop) {
setPrevMediaQuery(isDesktop);
setIsOpen(false);
}

if (isDesktop) {
return (
<>
{getLinks(!!data.user).map((link) => (
<NavLink
to={link.link}
key={link.name}
className={setClassBasedOnNav}
>
{link.name}
</NavLink>
))}
<div className="flex-1"></div>
<>
{data.user ? (
<button
className="text-white hover:text-white/70"
onClick={handleLogout}
>
Sign Out
</button>
) : (
<button
className="text-white hover:text-white/70"
onClick={handleLogin}
>
Sign In
</button>
)}
</>
</>
);
}

return (
<>
<div className="flex-1"></div>
{isOpen && (
<div className="w-full fixed top-[100px] left-0">
<ul className="font-medium flex flex-col p-4 md:p-0 mt-2 gap-4 rounded-lg bg-accent">
{getLinks(!!data.user).map((link) => (
<li key={link.link}>
<Link
onClick={() => setIsOpen(false)}
className="block py-2 pl-3 pr-4 text-white rounded"
to={link.link}
>
{link.name}
</Link>
</li>
))}
<>
{data.user ? (
<button
className="text-left block py-2 pl-3 pr-4 text-white rounded"
onClick={handleLogout}
>
Sign Out
</button>
) : (
<button
className="text-left block py-2 pl-3 pr-4 text-white rounded"
onClick={handleLogin}
>
Sign In
</button>
)}
</>
</ul>
</div>
)}
<button
onClick={() => {
setIsOpen((prev) => !prev);
}}
>
{!isOpen && <Bars3Icon className="w-6 h-6 min-w-[24px]" />}
{isOpen && <XMarkIcon className="w-6 h-6 min-w-[24px]" />}
</button>
</>
);
};
32 changes: 0 additions & 32 deletions src/services/ui/src/components/MainWrapper/index.test.tsx

This file was deleted.

Loading
Loading