Skip to content

Commit

Permalink
✨(frontend) add config provider
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
AntoLC committed Aug 20, 2024
1 parent 75aa2df commit 92876ab
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 6 deletions.
5 changes: 4 additions & 1 deletion src/frontend/apps/desk/src/core/AppProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useCunninghamTheme } from '@/cunningham';
import '@/i18n/initI18n';

import { Auth } from './auth/Auth';
import { ConfigProvider } from './config';

/**
* QueryClient:
Expand All @@ -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>
);
Expand Down
24 changes: 24 additions & 0 deletions src/frontend/apps/desk/src/core/config/ConfigProvider.tsx
Original file line number Diff line number Diff line change
@@ -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 changes: 11 additions & 0 deletions src/frontend/apps/desk/src/core/config/api/getConfig.tsx
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions src/frontend/apps/desk/src/core/config/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './getConfig';
2 changes: 2 additions & 0 deletions src/frontend/apps/desk/src/core/config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './ConfigProvider';
export * from './useConfigStore';
6 changes: 6 additions & 0 deletions src/frontend/apps/desk/src/core/config/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface Config {
LANGUAGES: [string, string][];
FEATURES: {
TEAMS: boolean;
};
}
26 changes: 26 additions & 0 deletions src/frontend/apps/desk/src/core/config/useConfigStore.tsx
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions src/frontend/apps/desk/src/core/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './AppProvider';
export * from './MainLayout';
export * from './PageLayout';
export * from './config';
24 changes: 19 additions & 5 deletions src/frontend/apps/desk/src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -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;

0 comments on commit 92876ab

Please sign in to comment.