✨(frontend) add config provider
Add a ConfigProvider to the frontend to provide configuration to the app. The configuration is loaded from the config endpoint and stored in a zustand store.
This commit is contained in:
@@ -6,6 +6,7 @@ import { useCunninghamTheme } from '@/cunningham';
|
||||
import '@/i18n/initI18n';
|
||||
|
||||
import { Auth } from './auth/Auth';
|
||||
import { ConfigProvider } from './config';
|
||||
|
||||
/**
|
||||
* QueryClient:
|
||||
@@ -29,7 +30,9 @@ export function AppProvider({ children }: { children: React.ReactNode }) {
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<ReactQueryDevtools />
|
||||
<CunninghamProvider theme={theme}>
|
||||
<Auth>{children}</Auth>
|
||||
<ConfigProvider>
|
||||
<Auth>{children}</Auth>
|
||||
</ConfigProvider>
|
||||
</CunninghamProvider>
|
||||
</QueryClientProvider>
|
||||
);
|
||||
|
||||
24
src/frontend/apps/desk/src/core/config/ConfigProvider.tsx
Normal file
24
src/frontend/apps/desk/src/core/config/ConfigProvider.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import { Loader } from '@openfun/cunningham-react';
|
||||
import { PropsWithChildren, useEffect } from 'react';
|
||||
|
||||
import { Box } from '@/components';
|
||||
|
||||
import { useConfigStore } from './useConfigStore';
|
||||
|
||||
export const ConfigProvider = ({ children }: PropsWithChildren) => {
|
||||
const { config, initConfig } = useConfigStore();
|
||||
|
||||
useEffect(() => {
|
||||
initConfig();
|
||||
}, [initConfig]);
|
||||
|
||||
if (!config) {
|
||||
return (
|
||||
<Box $height="100vh" $width="100vw" $align="center" $justify="center">
|
||||
<Loader />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return children;
|
||||
};
|
||||
11
src/frontend/apps/desk/src/core/config/api/getConfig.tsx
Normal file
11
src/frontend/apps/desk/src/core/config/api/getConfig.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import { fetchAPI } from '@/api';
|
||||
|
||||
import { Config } from '../types';
|
||||
|
||||
export const getConfig = async (): Promise<Config> => {
|
||||
const response = await fetchAPI(`config/`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Couldn't fetch conf data: ${response.statusText}`);
|
||||
}
|
||||
return response.json() as Promise<Config>;
|
||||
};
|
||||
1
src/frontend/apps/desk/src/core/config/api/index.ts
Normal file
1
src/frontend/apps/desk/src/core/config/api/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './getConfig';
|
||||
2
src/frontend/apps/desk/src/core/config/index.ts
Normal file
2
src/frontend/apps/desk/src/core/config/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './ConfigProvider';
|
||||
export * from './useConfigStore';
|
||||
6
src/frontend/apps/desk/src/core/config/types.ts
Normal file
6
src/frontend/apps/desk/src/core/config/types.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export interface Config {
|
||||
LANGUAGES: [string, string][];
|
||||
FEATURES: {
|
||||
TEAMS: boolean;
|
||||
};
|
||||
}
|
||||
26
src/frontend/apps/desk/src/core/config/useConfigStore.tsx
Normal file
26
src/frontend/apps/desk/src/core/config/useConfigStore.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import { create } from 'zustand';
|
||||
|
||||
import { getConfig } from './api';
|
||||
import { Config } from './types';
|
||||
|
||||
interface ConfStore {
|
||||
config?: Config;
|
||||
initConfig: () => void;
|
||||
}
|
||||
|
||||
const initialState = {
|
||||
config: undefined,
|
||||
};
|
||||
|
||||
export const useConfigStore = create<ConfStore>((set) => ({
|
||||
config: initialState.config,
|
||||
initConfig: () => {
|
||||
void getConfig()
|
||||
.then((config: Config) => {
|
||||
set({ config });
|
||||
})
|
||||
.catch(() => {
|
||||
console.error('Failed to fetch config data');
|
||||
});
|
||||
},
|
||||
}));
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './AppProvider';
|
||||
export * from './MainLayout';
|
||||
export * from './PageLayout';
|
||||
export * from './config';
|
||||
|
||||
@@ -1,6 +1,20 @@
|
||||
import MailDomains from './mail-domains';
|
||||
import Teams from './teams';
|
||||
import { useRouter as useNavigate } from 'next/navigation';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export default process.env.NEXT_PUBLIC_FEATURE_TEAM === 'true'
|
||||
? Teams
|
||||
: MailDomains;
|
||||
import { useConfigStore } from '@/core/config';
|
||||
import { NextPageWithLayout } from '@/types/next';
|
||||
|
||||
const Page: NextPageWithLayout = () => {
|
||||
const { config } = useConfigStore();
|
||||
const router = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
config?.FEATURES.TEAMS
|
||||
? router.push('/teams/')
|
||||
: router.push('mail-domains/');
|
||||
}, [config?.FEATURES.TEAMS, router]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export default Page;
|
||||
|
||||
Reference in New Issue
Block a user