Updating api auth and ms graph endpoint (#19)
* Updating api auth and ms graph endpoint * updating feature flag value * Updating get feature flags functions * Updating get feature flags functions
This commit was merged in pull request #19.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
.vscode/*
|
.vscode/*
|
||||||
node_modules
|
node_modules
|
||||||
**/.env
|
**/.env
|
||||||
|
.DS_Store
|
||||||
1
api/.gitignore
vendored
1
api/.gitignore
vendored
@@ -55,4 +55,5 @@ pids
|
|||||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
|
||||||
local.settings.json
|
local.settings.json
|
||||||
|
|||||||
@@ -24,9 +24,11 @@
|
|||||||
"@nestjs/azure-database": "^3.0.0",
|
"@nestjs/azure-database": "^3.0.0",
|
||||||
"@nestjs/azure-func-http": "^0.10.0",
|
"@nestjs/azure-func-http": "^0.10.0",
|
||||||
"@nestjs/common": "^10.0.0",
|
"@nestjs/common": "^10.0.0",
|
||||||
|
"@nestjs/config": "^3.2.2",
|
||||||
"@nestjs/core": "^10.0.0",
|
"@nestjs/core": "^10.0.0",
|
||||||
|
"@nestjs/passport": "^10.0.3",
|
||||||
"@nestjs/platform-express": "^10.0.0",
|
"@nestjs/platform-express": "^10.0.0",
|
||||||
"@noahspan/noahspan-modules": "^0.1.2",
|
"@noahspan/noahspan-modules": "^0.2.7",
|
||||||
"@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",
|
||||||
@@ -39,6 +41,7 @@
|
|||||||
"@types/express": "^4.17.17",
|
"@types/express": "^4.17.17",
|
||||||
"@types/jest": "^29.5.2",
|
"@types/jest": "^29.5.2",
|
||||||
"@types/node": "^20.3.1",
|
"@types/node": "^20.3.1",
|
||||||
|
"@types/passport-azure-ad": "^4.3.6",
|
||||||
"@types/supertest": "^6.0.0",
|
"@types/supertest": "^6.0.0",
|
||||||
"jest": "^29.5.0",
|
"jest": "^29.5.0",
|
||||||
"source-map-support": "^0.5.21",
|
"source-map-support": "^0.5.21",
|
||||||
|
|||||||
@@ -1,34 +1,57 @@
|
|||||||
import { Controller, Get, Query } from '@nestjs/common';
|
import { Controller, Get, Query } from '@nestjs/common';
|
||||||
import { AppService } from './app.service';
|
import {
|
||||||
import { AppConfigService, AuthService } from '@noahspan/noahspan-modules';
|
AppConfigService,
|
||||||
|
MsGraphService,
|
||||||
|
MsGraphClient
|
||||||
|
} from '@noahspan/noahspan-modules';
|
||||||
import { FeatureFlagValue } from '@azure/app-configuration';
|
import { FeatureFlagValue } from '@azure/app-configuration';
|
||||||
|
import { Public } from '@noahspan/noahspan-modules';
|
||||||
|
|
||||||
@Controller()
|
@Controller()
|
||||||
export class AppController {
|
export class AppController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly appConfigService: AppConfigService,
|
private readonly appConfigService: AppConfigService,
|
||||||
private readonly authService: AuthService
|
private readonly msGraphService: MsGraphService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
@Public()
|
||||||
@Get('featureFlags')
|
@Get('featureFlags')
|
||||||
async getFeatureFlags(@Query() query: any): Promise<FeatureFlagValue[]> {
|
async getFeatureFlags(
|
||||||
|
@Query() query: any
|
||||||
|
): Promise<{ key: string; enabled: boolean }[]> {
|
||||||
try {
|
try {
|
||||||
const token: string = await this.authService.getToken(
|
const featureFlagKeys: string[] =
|
||||||
'client_credentials',
|
query.keys && query.keys.toString().includes(';')
|
||||||
process.env.CLIENT_ID,
|
? query.keys.split(';')
|
||||||
process.env.CLIENT_SECRET,
|
: [query.keys];
|
||||||
'https://azconfig.io'
|
const featureFlagLabel: string = query.label;
|
||||||
);
|
const featureFlags: { key: string; enabled: boolean }[] =
|
||||||
const featureFlags: FeatureFlagValue[] =
|
|
||||||
await this.appConfigService.getFeatureFlags(
|
await this.appConfigService.getFeatureFlags(
|
||||||
token,
|
featureFlagKeys,
|
||||||
`${query.key}`,
|
featureFlagLabel
|
||||||
query.label
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return featureFlags;
|
return featureFlags;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Public()
|
||||||
|
@Get('profilePhoto')
|
||||||
|
async getProfilePhoto(@Query() query: any): Promise<any> {}
|
||||||
|
|
||||||
|
@Get('userProfile')
|
||||||
|
async getUserProfile(@Query() query: any) {
|
||||||
|
try {
|
||||||
|
const username: string = query.username;
|
||||||
|
const client: MsGraphClient =
|
||||||
|
await this.msGraphService.getMsGraphClient();
|
||||||
|
const userProfile = await client.api(`users/${username}`).get();
|
||||||
|
|
||||||
|
return userProfile;
|
||||||
|
} catch (error) {
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,42 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { AppController } from './app.controller';
|
import { AppController } from './app.controller';
|
||||||
import { AppService } from './app.service';
|
import { AppService } from './app.service';
|
||||||
import { AppConfigModule, AuthModule } from '@noahspan/noahspan-modules';
|
import {
|
||||||
|
AppConfigModule,
|
||||||
|
AuthModule,
|
||||||
|
AuthGuard,
|
||||||
|
MsGraphModule
|
||||||
|
} from '@noahspan/noahspan-modules';
|
||||||
|
import { ConfigModule } from '@nestjs/config';
|
||||||
|
import { APP_GUARD } from '@nestjs/core';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
|
ConfigModule.forRoot(),
|
||||||
AppConfigModule.register({
|
AppConfigModule.register({
|
||||||
url: process.env.APP_CONFIG_URL
|
url: process.env.APP_CONFIG_URL,
|
||||||
|
tenantId: process.env.TENANT_ID,
|
||||||
|
clientId: process.env.CLIENT_ID,
|
||||||
|
clientSecret: process.env.CLIENT_SECRET
|
||||||
}),
|
}),
|
||||||
AuthModule.register({
|
AuthModule.register({
|
||||||
tenantId: process.env.TENANT_ID
|
tenantId: process.env.TENANT_ID,
|
||||||
|
clientId: process.env.CLIENT_ID,
|
||||||
|
clientSecret: process.env.CLIENT_SECRET
|
||||||
|
}),
|
||||||
|
MsGraphModule.register({
|
||||||
|
tenantId: process.env.TENANT_ID,
|
||||||
|
clientId: process.env.CLIENT_ID,
|
||||||
|
clientSecret: process.env.CLIENT_SECRET
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
controllers: [AppController],
|
controllers: [AppController],
|
||||||
providers: [AppService]
|
providers: [
|
||||||
|
{
|
||||||
|
provide: APP_GUARD,
|
||||||
|
useClass: AuthGuard
|
||||||
|
},
|
||||||
|
AppService
|
||||||
|
]
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
"@fortawesome/free-solid-svg-icons": "^6.5.2",
|
"@fortawesome/free-solid-svg-icons": "^6.5.2",
|
||||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||||
"@nextui-org/react": "^2.3.6",
|
"@nextui-org/react": "^2.3.6",
|
||||||
"@noahspan/noahspan-components": "^0.2.4",
|
"@noahspan/noahspan-components": "^0.2.5",
|
||||||
"axios": "^1.7.2",
|
"axios": "^1.7.2",
|
||||||
"framer-motion": "^11.1.7",
|
"framer-motion": "^11.1.7",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
|||||||
@@ -11,10 +11,12 @@ const App: React.FC<unknown> = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const getFeatureFlags = async () => {
|
const getFeatureFlags = async () => {
|
||||||
try {
|
try {
|
||||||
|
const featureFlagKeys: string = 'flying-pilots';
|
||||||
const response: AxiosResponse = await axios.get(
|
const response: AxiosResponse = await axios.get(
|
||||||
`http://localhost:7071/api/featureFlags?key=flying*&label=${process.env.NODE_ENV}`
|
`http://localhost:7071/api/featureFlags?keys=${featureFlagKeys}&label=${process.env.NODE_ENV}`
|
||||||
);
|
);
|
||||||
const featureFlags: unknown[] = response.data;
|
const featureFlags: { key: string; enabled: boolean }[] = response.data;
|
||||||
|
console.log(featureFlags);
|
||||||
|
|
||||||
if (featureFlags.length > 0) {
|
if (featureFlags.length > 0) {
|
||||||
appContext.dispatch({
|
appContext.dispatch({
|
||||||
|
|||||||
@@ -1,122 +1,122 @@
|
|||||||
import React from 'react';
|
// import React from 'react';
|
||||||
import {
|
// import {
|
||||||
Accordion,
|
// Accordion,
|
||||||
AccordionItem,
|
// AccordionItem,
|
||||||
Button,
|
// Button,
|
||||||
DatePicker,
|
// DatePicker,
|
||||||
Input
|
// Input
|
||||||
} from '@nextui-org/react';
|
// } from '@nextui-org/react';
|
||||||
import { useForm, Controller, SubmitHandler } from 'react-hook-form';
|
// import { useForm, Controller, SubmitHandler } from 'react-hook-form';
|
||||||
|
|
||||||
const LogbookEntryForm: React.FC<unknown> = () => {
|
// const LogbookEntryForm: React.FC<unknown> = () => {
|
||||||
const { control, handleSubmit } = useForm();
|
// const { control, handleSubmit } = useForm();
|
||||||
|
|
||||||
const onSubmit = (data: unknown) => {
|
// const onSubmit = (data: unknown) => {
|
||||||
console.log(data);
|
// console.log(data);
|
||||||
};
|
// };
|
||||||
|
|
||||||
return (
|
// return (
|
||||||
<form className="m-10" onSubmit={handleSubmit(onSubmit)}>
|
// <form className="m-10" onSubmit={handleSubmit(onSubmit)}>
|
||||||
<div className="grid grid-cols-2 gap-4">
|
// <div className="grid grid-cols-2 gap-4">
|
||||||
<div className="self-center">
|
// <div className="self-center">
|
||||||
<label>Date</label>
|
// <label>Date</label>
|
||||||
</div>
|
// </div>
|
||||||
<div>
|
// <div>
|
||||||
<Controller
|
// <Controller
|
||||||
name="date"
|
// name="date"
|
||||||
control={control}
|
// control={control}
|
||||||
render={({ field }) => <DatePicker labelPlacement="outside-left" />}
|
// render={({ field }) => <DatePicker labelPlacement="outside-left" />}
|
||||||
/>
|
// />
|
||||||
</div>
|
// </div>
|
||||||
<div className="self-center">
|
// <div className="self-center">
|
||||||
<label>Aircraft Type</label>
|
// <label>Aircraft Type</label>
|
||||||
</div>
|
// </div>
|
||||||
<div>
|
// <div>
|
||||||
<Controller
|
// <Controller
|
||||||
name="aircraftType"
|
// name="aircraftType"
|
||||||
control={control}
|
// control={control}
|
||||||
render={({ field }) => (
|
// render={({ field }) => (
|
||||||
<Input fullWidth={true} labelPlacement="outside-left" />
|
// <Input fullWidth={true} labelPlacement="outside-left" />
|
||||||
)}
|
// )}
|
||||||
/>
|
// />
|
||||||
</div>
|
// </div>
|
||||||
<div className="self-center">
|
// <div className="self-center">
|
||||||
<label>Aircraft Identity</label>
|
// <label>Aircraft Identity</label>
|
||||||
</div>
|
// </div>
|
||||||
<div>
|
// <div>
|
||||||
<Controller
|
// <Controller
|
||||||
name="aircraftIdent"
|
// name="aircraftIdent"
|
||||||
control={control}
|
// control={control}
|
||||||
render={({ field }) => (
|
// render={({ field }) => (
|
||||||
<Input fullWidth={true} labelPlacement="outside-left" />
|
// <Input fullWidth={true} labelPlacement="outside-left" />
|
||||||
)}
|
// )}
|
||||||
/>
|
// />
|
||||||
</div>
|
// </div>
|
||||||
<div className="self-center">
|
// <div className="self-center">
|
||||||
<label>Route To</label>
|
// <label>Route To</label>
|
||||||
</div>
|
// </div>
|
||||||
<div>
|
// <div>
|
||||||
<Controller
|
// <Controller
|
||||||
name="routeTo"
|
// name="routeTo"
|
||||||
control={control}
|
// control={control}
|
||||||
render={({ field }) => <Input />}
|
// render={({ field }) => <Input />}
|
||||||
/>
|
// />
|
||||||
</div>
|
// </div>
|
||||||
<div className="self-center">
|
// <div className="self-center">
|
||||||
<label>Route From</label>
|
// <label>Route From</label>
|
||||||
</div>
|
// </div>
|
||||||
<div>
|
// <div>
|
||||||
<Controller
|
// <Controller
|
||||||
name="routeFrom"
|
// name="routeFrom"
|
||||||
control={control}
|
// control={control}
|
||||||
render={({ field }) => <Input />}
|
// render={({ field }) => <Input />}
|
||||||
/>
|
// />
|
||||||
</div>
|
// </div>
|
||||||
<div className="self-center">
|
// <div className="self-center">
|
||||||
<label>Duration of Flight</label>
|
// <label>Duration of Flight</label>
|
||||||
</div>
|
// </div>
|
||||||
<div>
|
// <div>
|
||||||
<Controller
|
// <Controller
|
||||||
name="flightDuration"
|
// name="flightDuration"
|
||||||
control={control}
|
// control={control}
|
||||||
render={({ field }) => <Input />}
|
// render={({ field }) => <Input />}
|
||||||
/>
|
// />
|
||||||
</div>
|
// </div>
|
||||||
<div className="self-center">
|
// <div className="self-center">
|
||||||
<label>Single Engine Land</label>
|
// <label>Single Engine Land</label>
|
||||||
</div>
|
// </div>
|
||||||
<div>
|
// <div>
|
||||||
<Controller
|
// <Controller
|
||||||
name="aircraftSEL"
|
// name="aircraftSEL"
|
||||||
control={control}
|
// control={control}
|
||||||
render={({ field }) => <Input />}
|
// render={({ field }) => <Input />}
|
||||||
/>
|
// />
|
||||||
</div>
|
// </div>
|
||||||
<div className="col-span-2">
|
// <div className="col-span-2">
|
||||||
<Accordion>
|
// <Accordion>
|
||||||
<AccordionItem title="Aircraft Category and Class">
|
// <AccordionItem title="Aircraft Category and Class">
|
||||||
<div className="self-center">
|
// <div className="self-center">
|
||||||
<label>Single Engine Land</label>
|
// <label>Single Engine Land</label>
|
||||||
</div>
|
// </div>
|
||||||
<div>
|
// <div>
|
||||||
<Controller
|
// <Controller
|
||||||
name="aircraftSEL"
|
// name="aircraftSEL"
|
||||||
control={control}
|
// control={control}
|
||||||
render={({ field }) => <Input />}
|
// render={({ field }) => <Input />}
|
||||||
/>
|
// />
|
||||||
</div>
|
// </div>
|
||||||
</AccordionItem>
|
// </AccordionItem>
|
||||||
</Accordion>
|
// </Accordion>
|
||||||
</div>
|
// </div>
|
||||||
<div className="col-span-2 justify-self-end">
|
// <div className="col-span-2 justify-self-end">
|
||||||
<Button color="default">Cancel</Button>
|
// <Button color="default">Cancel</Button>
|
||||||
<Button className="ml-10" color="primary">
|
// <Button className="ml-10" color="primary">
|
||||||
Save
|
// Save
|
||||||
</Button>
|
// </Button>
|
||||||
</div>
|
// </div>
|
||||||
</div>
|
// </div>
|
||||||
</form>
|
// </form>
|
||||||
);
|
// );
|
||||||
};
|
// };
|
||||||
|
|
||||||
export default LogbookEntryForm;
|
// export default LogbookEntryForm;
|
||||||
|
|||||||
@@ -1,85 +1,85 @@
|
|||||||
import {
|
// import {
|
||||||
Accordion,
|
// Accordion,
|
||||||
AccordionItem,
|
// AccordionItem,
|
||||||
Button,
|
// Button,
|
||||||
DatePicker,
|
// DatePicker,
|
||||||
Input,
|
// Input,
|
||||||
Select,
|
// Select,
|
||||||
SelectItem
|
// SelectItem
|
||||||
} from '@nextui-org/react';
|
// } from '@nextui-org/react';
|
||||||
import { useForm, Controller, SubmitHandler } from 'react-hook-form';
|
// import { useForm, Controller, SubmitHandler } from 'react-hook-form';
|
||||||
|
|
||||||
const PilotForm: React.FC<unknown> = () => {
|
// const PilotForm: React.FC<unknown> = () => {
|
||||||
const { control, handleSubmit } = useForm();
|
// const { control, handleSubmit } = useForm();
|
||||||
|
|
||||||
const onSubmit = (data: unknown) => {
|
// const onSubmit = (data: unknown) => {
|
||||||
console.log(data);
|
// console.log(data);
|
||||||
};
|
// };
|
||||||
|
|
||||||
return (
|
// return (
|
||||||
<form className="m-10" onSubmit={handleSubmit(onSubmit)}>
|
// <form className="m-10" onSubmit={handleSubmit(onSubmit)}>
|
||||||
<div className="grid grid-cols-2 gap-4">
|
// <div className="grid grid-cols-2 gap-4">
|
||||||
<div className="self-center">
|
// <div className="self-center">
|
||||||
<label>First Name</label>
|
// <label>First Name</label>
|
||||||
</div>
|
// </div>
|
||||||
<div>
|
// <div>
|
||||||
<Controller
|
// <Controller
|
||||||
name="firstName"
|
// name="firstName"
|
||||||
control={control}
|
// control={control}
|
||||||
render={({ field }) => <Input />}
|
// render={({ field }) => <Input />}
|
||||||
/>
|
// />
|
||||||
</div>
|
// </div>
|
||||||
<div className="self-center">
|
// <div className="self-center">
|
||||||
<label>Last Name</label>
|
// <label>Last Name</label>
|
||||||
</div>
|
// </div>
|
||||||
<div>
|
// <div>
|
||||||
<Controller
|
// <Controller
|
||||||
name="lastName"
|
// name="lastName"
|
||||||
control={control}
|
// control={control}
|
||||||
render={({ field }) => <Input />}
|
// render={({ field }) => <Input />}
|
||||||
/>
|
// />
|
||||||
</div>
|
// </div>
|
||||||
</div>
|
// </div>
|
||||||
<Accordion>
|
// <Accordion>
|
||||||
<AccordionItem title="Medical Certificate">
|
// <AccordionItem title="Medical Certificate">
|
||||||
<div className="grid grid-cols-2 gap-4">
|
// <div className="grid grid-cols-2 gap-4">
|
||||||
<div className="self-center">
|
// <div className="self-center">
|
||||||
<label>Class</label>
|
// <label>Class</label>
|
||||||
</div>
|
// </div>
|
||||||
<div>
|
// <div>
|
||||||
<Controller
|
// <Controller
|
||||||
name="medicalClass"
|
// name="medicalClass"
|
||||||
control={control}
|
// control={control}
|
||||||
render={({ field }) => (
|
// render={({ field }) => (
|
||||||
<Select>
|
// <Select>
|
||||||
<SelectItem key="first" value="First">
|
// <SelectItem key="first" value="First">
|
||||||
First
|
// First
|
||||||
</SelectItem>
|
// </SelectItem>
|
||||||
<SelectItem key="second" value="Second">
|
// <SelectItem key="second" value="Second">
|
||||||
Second
|
// Second
|
||||||
</SelectItem>
|
// </SelectItem>
|
||||||
<SelectItem key="Third" value="Third">
|
// <SelectItem key="Third" value="Third">
|
||||||
Third
|
// Third
|
||||||
</SelectItem>
|
// </SelectItem>
|
||||||
</Select>
|
// </Select>
|
||||||
)}
|
// )}
|
||||||
/>
|
// />
|
||||||
</div>
|
// </div>
|
||||||
<div className="self-center">
|
// <div className="self-center">
|
||||||
<label>Expires</label>
|
// <label>Expires</label>
|
||||||
</div>
|
// </div>
|
||||||
<div>
|
// <div>
|
||||||
<Controller
|
// <Controller
|
||||||
name="medicalExpiration"
|
// name="medicalExpiration"
|
||||||
control={control}
|
// control={control}
|
||||||
render={({ field }) => <DatePicker />}
|
// render={({ field }) => <DatePicker />}
|
||||||
/>
|
// />
|
||||||
</div>
|
// </div>
|
||||||
</div>
|
// </div>
|
||||||
</AccordionItem>
|
// </AccordionItem>
|
||||||
</Accordion>
|
// </Accordion>
|
||||||
</form>
|
// </form>
|
||||||
);
|
// );
|
||||||
};
|
// };
|
||||||
|
|
||||||
export default PilotForm;
|
// export default PilotForm;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import SiteNav from '../siteNav/SiteNav';
|
import SiteNav from '../siteNav/SiteNav';
|
||||||
import PilotForm from '../pilotForm/PilotForm';
|
// import PilotForm from '../pilotForm/PilotForm';
|
||||||
import { Button } from '@nextui-org/react';
|
import { Button } from '@nextui-org/react';
|
||||||
import {
|
import {
|
||||||
Drawer,
|
Drawer,
|
||||||
@@ -37,9 +37,7 @@ const Pilots: React.FC<unknown> = () => {
|
|||||||
<DrawerHeader>
|
<DrawerHeader>
|
||||||
<h2>Add Pilot</h2>
|
<h2>Add Pilot</h2>
|
||||||
</DrawerHeader>
|
</DrawerHeader>
|
||||||
<DrawerBody>
|
<DrawerBody>{/* <PilotForm /> */}</DrawerBody>
|
||||||
<PilotForm />
|
|
||||||
</DrawerBody>
|
|
||||||
<DrawerFooter>
|
<DrawerFooter>
|
||||||
<div className="flex gap-4 justify-end justify-self-center">
|
<div className="flex gap-4 justify-end justify-self-center">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ const SiteNav: React.FC<unknown> = () => {
|
|||||||
<NavbarContent justify="center">
|
<NavbarContent justify="center">
|
||||||
<NavbarItem>
|
<NavbarItem>
|
||||||
{appContext.state.featureFlags.find(
|
{appContext.state.featureFlags.find(
|
||||||
(featureFlag) => featureFlag.id === 'flying-pilots'
|
(featureFlag) => featureFlag.key === 'flying-pilots'
|
||||||
)?.enabled && (
|
)?.enabled && (
|
||||||
<Link>
|
<Link>
|
||||||
<ReactRouterLink to="/">Pilots</ReactRouterLink>
|
<ReactRouterLink to="/">Pilots</ReactRouterLink>
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
export interface IAppContextState {
|
export interface IAppContextState {
|
||||||
featureFlags: unknown[];
|
featureFlags: { key: string; enabled: boolean }[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { IAppContextState } from './IAppContextState';
|
import { IAppContextState } from './IAppContextState';
|
||||||
|
|
||||||
export type Action = { type: 'SET_FEATURE_FLAGS'; payload: unknown[] };
|
export type Action = {
|
||||||
|
type: 'SET_FEATURE_FLAGS';
|
||||||
|
payload: { key: string; enabled: boolean }[];
|
||||||
|
};
|
||||||
|
|
||||||
export const reducer = (
|
export const reducer = (
|
||||||
state: IAppContextState,
|
state: IAppContextState,
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { useAppContext } from '../appContext/UseAppContext';
|
import { useAppContext } from '../appContext/UseAppContext';
|
||||||
|
|
||||||
export const useFeatureFlag = (featureFlagId: string) => {
|
export const useFeatureFlag = (featureFlagKey: string) => {
|
||||||
const appContext = useAppContext();
|
const appContext = useAppContext();
|
||||||
const featureFlag = appContext.state.featureFlags.find(
|
const featureFlag = appContext.state.featureFlags.find(
|
||||||
(featureFlag) => featureFlag.id === featureFlagId
|
(featureFlag) => featureFlag.key === featureFlagKey
|
||||||
);
|
);
|
||||||
|
|
||||||
return featureFlag;
|
return featureFlag;
|
||||||
|
|||||||
699
package-lock.json
generated
699
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user