Refactoring

This commit is contained in:
2025-01-19 15:03:23 -06:00
parent 58f4a6c7cb
commit d0dcf1b2c9
7 changed files with 156 additions and 99 deletions

View File

@@ -1,37 +1,27 @@
import { useEffect, useState } from 'react';
import { ISiteNavProps } from './ISiteNavProps';
import { useNavigate } from 'react-router-dom';
import { useAppContext } from '../../hooks/appContext/UseAppContext';
import {
Avatar,
Button,
IconButton,
Menu,
MenuItem,
Navbar,
PlaneIcon,
SignOutIcon,
Spinner,
Typography
} from '@noahspan/noahspan-components';
import { useIsAuthenticated, useMsal } from '@azure/msal-react';
import { InteractionStatus } from '@azure/msal-browser';
import { useAccessToken } from '../../hooks/accessToken/UseAcessToken';
import { useHttpClient } from '../../hooks/httpClient/UseHttpClient';
import { AxiosInstance, AxiosResponse } from 'axios';
import { User } from '@microsoft/microsoft-graph-types';
import { EventMessage, EventPayload, EventType } from '@azure/msal-browser';
type EventPayloadExtended = EventPayload & { accessToken: string };
import { loginRequest } from '../../hooks/auth/authConfig';
const SiteNav: React.FC<unknown> = () => {
const [loading, setLoading] = useState<boolean>(false);
const [userPhoto, setUserPhoto] = useState<string>();
const httpClient: AxiosInstance = useHttpClient();
const appContext = useAppContext();
const isAuthenticated = useIsAuthenticated();
const { getAccessToken } = useAccessToken();
const { inProgress, instance } = useMsal();
const { instance } = useMsal();
const navigate = useNavigate();
const pages = [
{
@@ -43,28 +33,23 @@ const SiteNav: React.FC<unknown> = () => {
url: '/pilots'
}
];
const handleSignIn = async () => {
// instance.handleRedirectPromise().then((response) => {
// if (response) {
// console.log(response)
// console.log('successful login', response);
// } else {
// instance.loginRedirect({
// scopes: [`api://${import.meta.env.VITE_CLIENT_ID}/user_impersonation`]
// });
// }
// }).catch((error) => {
// console.log(error);
// })
try {
await instance.loginPopup();
} catch (err) {
console.log(err);
}
};
const handleSignOut = () => {
instance.logoutRedirect();
const handleSignInRedirect = () => {
instance
.loginRedirect({
...loginRequest,
prompt: 'create',
})
.catch((error) => console.log(error));
};
const handleSignOutRedirect = () => {
instance.logoutRedirect({
postLogoutRedirectUri: '/'
})
window.location.reload();
}
const getUserProfile = async (accessToken: string): Promise<User> => {
try {
const response: AxiosResponse = await httpClient.get(`api/userProfile`, {
@@ -79,6 +64,7 @@ const SiteNav: React.FC<unknown> = () => {
throw new Error();
}
};
const getUserPhoto = async (accessToken: string): Promise<string> => {
try {
const response: AxiosResponse = await httpClient.get(`api/userPhoto`, {
@@ -103,7 +89,7 @@ const SiteNav: React.FC<unknown> = () => {
const Settings = () => {
return (
<MenuItem onClick={handleSignOut}>
<MenuItem onClick={handleSignOutRedirect}>
<SignOutIcon />
<Typography sx={{ marginLeft: '10px', textAlign: 'center' }}>
Sign Out
@@ -112,46 +98,9 @@ const SiteNav: React.FC<unknown> = () => {
);
};
useEffect(() => {
const callback = instance.addEventCallback(
async (message: EventMessage) => {
if (message.eventType === EventType.LOGIN_SUCCESS) {
try {
setLoading(true);
const eventPayload: EventPayloadExtended =
message.payload as EventPayloadExtended;
const userProfile: User = await getUserProfile(
eventPayload.accessToken
);
const userPhoto = await getUserPhoto(eventPayload.accessToken);
appContext.dispatch({
type: 'SET_USER_PROFILE',
payload: userProfile
});
} catch (error) {
console.log(error);
} finally {
setLoading(false);
}
}
}
);
return () => {
if (callback) {
instance.removeEventCallback(callback);
appContext.dispatch({ type: 'SET_USER_PROFILE', payload: {} });
}
};
}, []);
useEffect(() => {
const setUserProfile = async () => {
try {
setLoading(true);
const accessToken: string = await getAccessToken();
const userProfile = await getUserProfile(accessToken);
const userPhoto = await getUserPhoto(accessToken);
@@ -164,8 +113,6 @@ const SiteNav: React.FC<unknown> = () => {
});
} catch (error) {
console.log(error);
} finally {
setLoading(false);
}
};
@@ -180,7 +127,7 @@ const SiteNav: React.FC<unknown> = () => {
return (
<Navbar
handlePageClick={handlePageClick}
handleSignIn={handleSignIn}
handleSignIn={handleSignInRedirect}
isAuthenticated={isAuthenticated}
logo={<PlaneIcon size="2x" />}
pages={pages}

View File

@@ -0,0 +1,7 @@
import { AuthProvider } from "./authProvider"
export const useAuthProvider = () => {
return {
AuthProvider
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { LogLevel } from '@azure/msal-browser';
/**
* Configuration object to be passed to MSAL instance on creation.
* For a full list of MSAL.js configuration parameters, visit:
* https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/configuration.md
*/
export const msalConfig = {
auth: {
clientId: import.meta.env.VITE_CLIENT_ID, // This is the ONLY mandatory field that you need to supply.
authority: `https://login.microsoftonline.com/${import.meta.env.VITE_TENANT_ID}`, // Replace the placeholder with your tenant subdomain
redirectUri: import.meta.env.VITE_REDIRECT_URL, // Points to window.location.origin. You must register this URI on Microsoft Entra admin center/App Registration.
postLogoutRedirectUri: '/', // Indicates the page to navigate after logout.
navigateToLoginRequestUrl: false, // If "true", will navigate back to the original request location before processing the auth code response.
},
cache: {
cacheLocation: 'sessionStorage', // Configures cache location. "sessionStorage" is more secure, but "localStorage" gives you SSO between tabs.
storeAuthStateInCookie: false, // Set this to "true" if you are having issues on IE11 or Edge
},
system: {
loggerOptions: {
loggerCallback: (level: any, message: any, containsPii: any) => {
if (containsPii) {
return;
}
switch (level) {
case LogLevel.Error:
console.error(message);
return;
case LogLevel.Info:
console.info(message);
return;
case LogLevel.Verbose:
console.debug(message);
return;
case LogLevel.Warning:
console.warn(message);
return;
default:
return;
}
},
},
},
};
/**
* Scopes you add here will be prompted for user consent during sign-in.
* By default, MSAL.js will add OIDC scopes (openid, profile, email) to any login request.
* For more information about OIDC scopes, visit:
* https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent#openid-connect-scopes
*/
export const loginRequest = {
scopes: [`api://${import.meta.env.VITE_CLIENT_ID}/user_impersonation`]
};
/**
* An optional silentRequest object can be used to achieve silent SSO
* between applications by providing a "login_hint" property.
*/
// export const silentRequest = {
// scopes: ["openid", "profile"],
// loginHint: "example@domain.net"
// };

View File

@@ -0,0 +1,32 @@
import { AuthenticationResult, EventType, PublicClientApplication } from "@azure/msal-browser";
import { ReactNode } from "react";
import { msalConfig } from "./authConfig";
import { MsalProvider } from "@azure/msal-react";
interface AuthProviderProps {
children: ReactNode
}
export const AuthProvider = ({ children }: AuthProviderProps ) => {
const msalInstance = new PublicClientApplication(msalConfig);
// Default to using the first account if no account is active on page load
if (!msalInstance.getActiveAccount() && msalInstance.getAllAccounts().length > 0) {
// Account selection logic is app dependent. Adjust as needed for different use cases.
msalInstance.setActiveAccount(msalInstance.getAllAccounts()[0]);
}
// Listen for sign-in event and set active account
msalInstance.addEventCallback((event) => {
const authenticationResult = event.payload as AuthenticationResult;
const account = authenticationResult?.account;
if (event.eventType === EventType.LOGIN_SUCCESS && account) {
msalInstance.setActiveAccount(account);
}
});
return <MsalProvider instance={msalInstance}>
{children}
</MsalProvider>
}

View File

@@ -5,27 +5,21 @@ import AppContextProvider from './context/appContext/AppContextProvider.tsx';
import { BrowserRouter } from 'react-router-dom';
import './index.css';
import '@noahspan/noahspan-components/noahspan-components.css';
import { PublicClientApplication } from '@azure/msal-browser';
import { EventMessage, EventPayload, EventType, LogLevel, PublicClientApplication } from '@azure/msal-browser';
import { MsalProvider } from '@azure/msal-react';
import { useAuthProvider } from './hooks/auth/UseAuthProvider.tsx';
const msalInstance: PublicClientApplication = new PublicClientApplication({
auth: {
clientId: import.meta.env.VITE_CLIENT_ID,
authority: `https://login.microsoftonline.com/${import.meta.env.VITE_TENANT_ID}`,
redirectUri: import.meta.env.VITE_REDIRECT_URL
}
});
const { AuthProvider } = useAuthProvider();
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<AuthProvider>
<AppContextProvider>
<BrowserRouter>
<App />
</BrowserRouter>
</AppContextProvider>
</AuthProvider>
</React.StrictMode>
);
msalInstance.initialize().then(() => {
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<MsalProvider instance={msalInstance}>
<AppContextProvider>
<BrowserRouter>
<App />
</BrowserRouter>
</AppContextProvider>
</MsalProvider>
</React.StrictMode>
);
});

View File

@@ -8,55 +8,66 @@ locals {
container_app_app_container_image = {
dev = "noahspan/flying-app:v0.0.1"
test = "noahspan/flying-app:v0.0.1"
prod = "noahspan/flying-app:v0.0.1"
}
container_app_app_container_name = {
dev = "flying-app-dev"
test = "flying-app-test"
prod = "flying-app-prod"
}
container_app_api_name = {
dev = "flying-api-dev"
test = "flying-api-test"
prod = "flying-api-prod"
}
container_app_api_container_image = {
dev = "noahspan/flying-api:v0.0.1"
test = "noahspan/flying-api:v0.0.1"
prod = "noahspan/flying-api:v0.0.1"
}
container_app_api_container_name = {
dev = "flying-api-dev"
test = "flying-api-test"
prod = "flying-api-prod"
}
container_app_api_dapr_app_id = {
dev = "flyingapidev"
test = "flyingapitest"
prod = "flyingpapiprod"
}
container_app_environment_name = {
dev = "flying-dev"
test = "flying-test"
prod = "flying-prod"
}
logbook_feature_flag_active = {
dev = "true"
test = "true"
prod = "true"
}
log_analytics_workspace_name = {
dev = "flying-log-analytics-workspace-dev"
test = "flying-log-analytics-workspace-test"
prod = "flying-log-analytics-workspace-prod"
}
pilots_feature_flag_active = {
dev = "true"
test = "true"
prod = "true"
}
storage_account_name = {
dev = "noahspanflyingdev"
test = "noahspanflyingtest"
prod = "noahspanflyingprod"
}
}

View File

@@ -30,10 +30,6 @@ output "container_app_environment_name" {
value = local.container_app_environment_name[var.environment]
}
output "key_vault_name" {
value = local.key_vault_name[var.environment]
}
output "logbook_feature_flag_active" {
value = local.logbook_feature_flag_active[var.environment]
}