import * as React from 'react'
import {useState, useEffect, useContext} from "react";
import initialiseApplication from "../tools/AppInitialiser";
type Config = {
environment: any
appearance?: any
header?: any
footer?: any
banner?: any
support: any
apis: any
authentication: any
env: string
basePath: string,
application?: any
}
export const ConfigContext = React.createContext<Config | null>(null)
/**
* The `ConfigContextProvider` loads the application config using the {@link initialiseApplication} function from the
* `AppInitialiser`. The config is then made available to the rest of the application through the context provider.
*
* @property {string} basePath Base path of the application (e.g. App-specific hosting URL)
* @property {*} children React child components that the context has been wrapped around
* @component
*
* @category Context Providers
*/
export const ConfigContextProvider = (props: any) => {
// State for each of the configuration sections
const [environment, setEnvironment] = useState<any>(undefined)
const [appearance, setAppearance] = useState<any>(undefined)
const [header, setHeader] = useState(undefined)
const [footer, setFooter] = useState(undefined)
const [banner, setBanner] = useState(undefined)
const [support, setSupport] = useState<any>(undefined)
const [apis, setApis] = useState<any>([])
const [application, setApplication] = useState<any>(undefined)
const [authentication, setAuthentication] = useState<any>(undefined)
const [basePath, setBasePath] = useState<any>(props.basePath || '/')
// Separate state for environment type (as there is also an environment config)
const [env, setEnv] = useState('test')
// Flag for whether the config loaded successfully or not
const [configLoaded, setConfigLoaded] = useState(false)
const [configLoadFailed, setConfigLoadFailed] = useState(false)
//TODO: Add config fixing to handle legacy oidc client keys (e.g. make them come out of this process in a single place)
useEffect(() => {
// Define async config load
async function loadConfig() {
setBasePath(props.basePath)
initialiseApplication(props.basePath).then(config => {
if (config) {
// Load the config root object
//@ts-ignore
let configuration: Config = config.configuration
// Set the environment type (test, uat, prod)
setEnv(configuration.environment.type)
// Set API configurations
setApis(configuration.apis)
// Set app configurations
setAppearance(configuration.appearance)
setEnvironment(configuration.environment)
setHeader(configuration.header)
setFooter(configuration.footer)
setBanner(configuration.banner)
setSupport(configuration.support)
// Set the application specific config
// i.e. config specific to the app internals
setApplication(configuration.application)
// Load authentication configuration
// Defaults client and authority to '' if missing
// Handles legacy declarations (environment.oidcClient)
let authConfig = configuration.authentication
if (authConfig) {
setAuthentication(authConfig)
} else {
setAuthentication({})
}
setConfigLoaded(true)
}
}).catch((err) => {
console.log("Failed to load config")
console.log(err)
setConfigLoadFailed(true)
})
}
// Call config load function
loadConfig()
}, [])
// Write out state changes to new object, triggers context rerenders as the object changes
const contextValue: Config = configLoaded ? {
environment,
appearance,
header,
footer,
support,
apis,
application,
authentication,
env,
basePath,
banner
} : null
return (
<ConfigContext.Provider value={contextValue}>
{configLoaded || configLoadFailed ? props.children : null}
</ConfigContext.Provider>
)
}
/**
* Custom hook for access SPA config data.
*
* This hook exposes the application configuration data.
*
* The structure of the config data is clarified [here]{@tutorial configfile}
*
* ```
* const config = useJcuConfig()
* ```
*
* @category Hooks
*/
export function useJcuConfig(): Config {
//TODO: JSDOC
//TODO: Add config load checks to hook
const config = useContext(ConfigContext)
return config
}
Source