adding app context and feature flag hooks
This commit is contained in:
@@ -26,7 +26,7 @@
|
|||||||
"@nestjs/common": "^10.0.0",
|
"@nestjs/common": "^10.0.0",
|
||||||
"@nestjs/core": "^10.0.0",
|
"@nestjs/core": "^10.0.0",
|
||||||
"@nestjs/platform-express": "^10.0.0",
|
"@nestjs/platform-express": "^10.0.0",
|
||||||
"@noahspan/noahspan-modules": "^0.1.1",
|
"@noahspan/noahspan-modules": "^0.1.2",
|
||||||
"@schematics/angular": "^17.3.7",
|
"@schematics/angular": "^17.3.7",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"reflect-metadata": "0.1.13",
|
"reflect-metadata": "0.1.13",
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ export class AppController {
|
|||||||
private readonly authService: AuthService
|
private readonly authService: AuthService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Get('featureFlag')
|
@Get('featureFlags')
|
||||||
async getFeatureFlag(@Query() query: any): Promise<FeatureFlagValue[]> {
|
async getFeatureFlags(@Query() query: any): Promise<FeatureFlagValue[]> {
|
||||||
try {
|
try {
|
||||||
const token: string = await this.authService.getToken(
|
const token: string = await this.authService.getToken(
|
||||||
'client_credentials',
|
'client_credentials',
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@azure/msal-react": "^2.0.15",
|
"@azure/msal-react": "^2.0.15",
|
||||||
"@nextui-org/react": "^2.3.6",
|
"@nextui-org/react": "^2.3.6",
|
||||||
|
"axios": "^1.7.2",
|
||||||
"framer-motion": "^11.1.7",
|
"framer-motion": "^11.1.7",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
|
|||||||
@@ -1,12 +1,40 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
import { Route, Routes } from 'react-router-dom';
|
import { Route, Routes } from 'react-router-dom';
|
||||||
import Logbook from './components/logbook/Logbook';
|
|
||||||
import Pilots from './components/pilots/Pilots';
|
import Pilots from './components/pilots/Pilots';
|
||||||
|
import { useAppContext } from './hooks/appContext/UseAppContext';
|
||||||
|
import axios, { AxiosResponse } from 'axios';
|
||||||
|
import { useFeatureFlag } from './hooks/featureFlag/UseFeatureFlag';
|
||||||
|
|
||||||
const App: React.FC<unknown> = () => {
|
const App: React.FC<unknown> = () => {
|
||||||
|
const appContext = useAppContext();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const getFeatureFlags = async () => {
|
||||||
|
try {
|
||||||
|
const response: AxiosResponse = await axios.get(
|
||||||
|
`http://localhost:7071/api/featureFlags?key=flying*&label=${process.env.NODE_ENV}`
|
||||||
|
);
|
||||||
|
const featureFlags: unknown[] = response.data;
|
||||||
|
|
||||||
|
if (featureFlags.length > 0) {
|
||||||
|
appContext.dispatch({
|
||||||
|
type: 'SET_FEATURE_FLAGS',
|
||||||
|
payload: featureFlags
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
getFeatureFlags();
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="logbook" element={<Logbook />} />
|
{useFeatureFlag('flying-pilots')?.enabled && (
|
||||||
<Route path="pilots" element={<Pilots />} />
|
<Route path="/" element={<Pilots />} />
|
||||||
|
)}
|
||||||
</Routes>
|
</Routes>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
} from '@nextui-org/react';
|
} from '@nextui-org/react';
|
||||||
import { Link as ReactRouterLink } from 'react-router-dom';
|
import { Link as ReactRouterLink } from 'react-router-dom';
|
||||||
import { useIsAuthenticated, useMsal } from '@azure/msal-react';
|
import { useIsAuthenticated, useMsal } from '@azure/msal-react';
|
||||||
|
import { useAppContext } from '../../hooks/appContext/UseAppContext';
|
||||||
|
|
||||||
const SiteNav: React.FC<unknown> = () => {
|
const SiteNav: React.FC<unknown> = () => {
|
||||||
const isAuthenticated = useIsAuthenticated();
|
const isAuthenticated = useIsAuthenticated();
|
||||||
@@ -16,6 +17,7 @@ const SiteNav: React.FC<unknown> = () => {
|
|||||||
const initializeLogin = () => {
|
const initializeLogin = () => {
|
||||||
instance.loginRedirect();
|
instance.loginRedirect();
|
||||||
};
|
};
|
||||||
|
const appContext = useAppContext();
|
||||||
|
|
||||||
console.log(accounts);
|
console.log(accounts);
|
||||||
|
|
||||||
@@ -24,24 +26,13 @@ const SiteNav: React.FC<unknown> = () => {
|
|||||||
<NavbarBrand>Site Logo Goes Here</NavbarBrand>
|
<NavbarBrand>Site Logo Goes Here</NavbarBrand>
|
||||||
<NavbarContent justify="center">
|
<NavbarContent justify="center">
|
||||||
<NavbarItem>
|
<NavbarItem>
|
||||||
<Link>
|
{appContext.state.featureFlags.find(
|
||||||
<ReactRouterLink to="/">Flights</ReactRouterLink>
|
(featureFlag) => featureFlag.id === 'flying-pilots'
|
||||||
</Link>
|
)?.enabled && (
|
||||||
</NavbarItem>
|
<Link>
|
||||||
<NavbarItem>
|
<ReactRouterLink to="/">Pilots</ReactRouterLink>
|
||||||
<Link>
|
</Link>
|
||||||
<ReactRouterLink to="/logbook">Logbook</ReactRouterLink>
|
)}
|
||||||
</Link>
|
|
||||||
</NavbarItem>
|
|
||||||
<NavbarItem>
|
|
||||||
<Link>
|
|
||||||
<ReactRouterLink to="/checklists">Checklists</ReactRouterLink>
|
|
||||||
</Link>
|
|
||||||
</NavbarItem>
|
|
||||||
<NavbarItem>
|
|
||||||
<Link>
|
|
||||||
<ReactRouterLink to="/pilots">Pilots</ReactRouterLink>
|
|
||||||
</Link>
|
|
||||||
</NavbarItem>
|
</NavbarItem>
|
||||||
</NavbarContent>
|
</NavbarContent>
|
||||||
<NavbarContent justify="end">
|
<NavbarContent justify="end">
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
|
import { useMemo, useReducer } from 'react';
|
||||||
|
import { AppContext } from './AppContext';
|
||||||
import { IAppContextProviderProps } from './IAppContextProviderProps';
|
import { IAppContextProviderProps } from './IAppContextProviderProps';
|
||||||
|
import { IAppContextProps } from './IAppContextProps';
|
||||||
import { IAppContextState } from './IAppContextState';
|
import { IAppContextState } from './IAppContextState';
|
||||||
|
import { reducer } from './reducer';
|
||||||
|
|
||||||
const AppContextProvider: React.FC<IAppContextProviderProps> = (
|
const AppContextProvider: React.FC<IAppContextProviderProps> = (
|
||||||
props: IAppContextProviderProps
|
props: IAppContextProviderProps
|
||||||
@@ -8,15 +12,12 @@ const AppContextProvider: React.FC<IAppContextProviderProps> = (
|
|||||||
featureFlags: []
|
featureFlags: []
|
||||||
};
|
};
|
||||||
const [state, dispatch] = useReducer(reducer, intialState);
|
const [state, dispatch] = useReducer(reducer, intialState);
|
||||||
const contextValue = (IAppContextProps = useMemo(() => {
|
const contextValue: IAppContextProps = useMemo(() => {
|
||||||
return (
|
return {
|
||||||
{
|
state,
|
||||||
state,
|
dispatch
|
||||||
dispatch
|
};
|
||||||
},
|
}, [state, dispatch]);
|
||||||
[state, dispatch]
|
|
||||||
);
|
|
||||||
}));
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppContext.Provider value={contextValue}>
|
<AppContext.Provider value={contextValue}>
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
import { Action } from './reducer';
|
||||||
|
import { IAppContextState } from './IAppContextState';
|
||||||
|
|
||||||
export interface IAppContextProps {
|
export interface IAppContextProps {
|
||||||
state: IAppContextState;
|
state: IAppContextState;
|
||||||
dispatch: React.Dispatch<Action>;
|
dispatch: React.Dispatch<Action>;
|
||||||
|
|||||||
11
app/src/hooks/appContext/UseAppContext.tsx
Normal file
11
app/src/hooks/appContext/UseAppContext.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { useContext } from 'react';
|
||||||
|
import { AppContext } from '../../context/appContext/AppContext';
|
||||||
|
|
||||||
|
export const useAppContext = () => {
|
||||||
|
const { state, dispatch } = useContext(AppContext);
|
||||||
|
|
||||||
|
return {
|
||||||
|
state,
|
||||||
|
dispatch
|
||||||
|
};
|
||||||
|
};
|
||||||
10
app/src/hooks/featureFlag/UseFeatureFlag.tsx
Normal file
10
app/src/hooks/featureFlag/UseFeatureFlag.tsx
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { useAppContext } from '../appContext/UseAppContext';
|
||||||
|
|
||||||
|
export const useFeatureFlag = (featureFlagId: string) => {
|
||||||
|
const appContext = useAppContext();
|
||||||
|
const featureFlag = appContext.state.featureFlags.find(
|
||||||
|
(featureFlag) => featureFlag.id === featureFlagId
|
||||||
|
);
|
||||||
|
|
||||||
|
return featureFlag;
|
||||||
|
};
|
||||||
@@ -4,8 +4,9 @@ import { MsalProvider } from '@azure/msal-react';
|
|||||||
import { Configuration, PublicClientApplication } from '@azure/msal-browser';
|
import { Configuration, PublicClientApplication } from '@azure/msal-browser';
|
||||||
import { NextUIProvider } from '@nextui-org/react';
|
import { NextUIProvider } from '@nextui-org/react';
|
||||||
import App from './App.tsx';
|
import App from './App.tsx';
|
||||||
import './index.css';
|
|
||||||
import { BrowserRouter } from 'react-router-dom';
|
import { BrowserRouter } from 'react-router-dom';
|
||||||
|
import AppContextProvider from './context/appContext/AppContextProvider.tsx';
|
||||||
|
import './index.css';
|
||||||
|
|
||||||
const configuration: Configuration = {
|
const configuration: Configuration = {
|
||||||
auth: {
|
auth: {
|
||||||
@@ -21,11 +22,13 @@ const pca = new PublicClientApplication(configuration);
|
|||||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<MsalProvider instance={pca}>
|
<MsalProvider instance={pca}>
|
||||||
<NextUIProvider>
|
<AppContextProvider>
|
||||||
<BrowserRouter>
|
<NextUIProvider>
|
||||||
<App />
|
<BrowserRouter>
|
||||||
</BrowserRouter>
|
<App />
|
||||||
</NextUIProvider>
|
</BrowserRouter>
|
||||||
|
</NextUIProvider>
|
||||||
|
</AppContextProvider>
|
||||||
</MsalProvider>
|
</MsalProvider>
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export default {
|
|||||||
content: [
|
content: [
|
||||||
'./index.html',
|
'./index.html',
|
||||||
'./src/**/*.{js,ts,jsx,tsx}',
|
'./src/**/*.{js,ts,jsx,tsx}',
|
||||||
'./node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}'
|
'../node_modules/@nextui-org/theme/dist/**/*.{js,ts,jsx,tsx}'
|
||||||
],
|
],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {}
|
extend: {}
|
||||||
|
|||||||
9
package-lock.json
generated
9
package-lock.json
generated
@@ -37,7 +37,7 @@
|
|||||||
"@nestjs/common": "^10.0.0",
|
"@nestjs/common": "^10.0.0",
|
||||||
"@nestjs/core": "^10.0.0",
|
"@nestjs/core": "^10.0.0",
|
||||||
"@nestjs/platform-express": "^10.0.0",
|
"@nestjs/platform-express": "^10.0.0",
|
||||||
"@noahspan/noahspan-modules": "^0.1.1",
|
"@noahspan/noahspan-modules": "^0.1.2",
|
||||||
"@schematics/angular": "^17.3.7",
|
"@schematics/angular": "^17.3.7",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"reflect-metadata": "0.1.13",
|
"reflect-metadata": "0.1.13",
|
||||||
@@ -67,6 +67,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@azure/msal-react": "^2.0.15",
|
"@azure/msal-react": "^2.0.15",
|
||||||
"@nextui-org/react": "^2.3.6",
|
"@nextui-org/react": "^2.3.6",
|
||||||
|
"axios": "^1.7.2",
|
||||||
"framer-motion": "^11.1.7",
|
"framer-motion": "^11.1.7",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
@@ -4402,9 +4403,9 @@
|
|||||||
"link": true
|
"link": true
|
||||||
},
|
},
|
||||||
"node_modules/@noahspan/noahspan-modules": {
|
"node_modules/@noahspan/noahspan-modules": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@noahspan/noahspan-modules/-/noahspan-modules-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@noahspan/noahspan-modules/-/noahspan-modules-0.1.2.tgz",
|
||||||
"integrity": "sha512-9rljhDl2AZeIMWZgTR59pFvC7N3i+j332vsfNnHMAh5ApaNjgmWZ6La/8MkGJmcZ8pxT9cqXDaH27A8YWKbJBQ==",
|
"integrity": "sha512-cD1PUgcFvy/9LTvxfzjk43+n+wZ4eTfWIZk1XFyM+NjjvP9cks2QnpQJ+di+7LYuzO8EPRX0/Ln34ywwwOCZaQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@azure/app-configuration": "^1.6.0",
|
"@azure/app-configuration": "^1.6.0",
|
||||||
"@nestjs/common": "^10.0.0",
|
"@nestjs/common": "^10.0.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user