Display a generic fallback component when initial config load fails (#8588)
Fixes: #8487 #5027
1. Summary
The purpose of these changes is to elevate the dev/user experience when
the initial config load call fails for whatever reason by displaying a
fallback component.
2. Solution
I ended up making more changes than I initially planned. I had to update
the order of the contexts a bit because `GenericErrorFallback` is
dependent on `AppThemeProvider` for styling and `AppThemeProvider` is
dependent on `ObjectMetadataItemsProvider` for
[`useObjectMetadataItem`](ae2f193d68/packages/twenty-front/src/modules/object-metadata/hooks/useObjectMetadataItem.ts (L22))
hook (`AppThemeProvider` -> `useColorScheme` -> `useUpdateOneRecord` ->
`useObjectMetadataItem`). I had to create a wrapper component for
`AppThemeProvider` and stylize it in a way that it looks responsive on
both mobile and desktop devices. Finally, I had to introduce the
`isErrored` flag to differentiate the loading and error states.
There are some improvements we can make later -
- Display a loading state for the initial config load
- Implement a refetch logic for the initial config loading failure
3. Recording
https://github.com/user-attachments/assets/c2f43573-8006-4118-8e18-8576099d78fd
https://github.com/user-attachments/assets/9c5853d3-539b-4880-aa38-c416c3e13594
---------
Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
@ -3,8 +3,8 @@ import { authProvidersState } from '@/client-config/states/authProvidersState';
|
||||
import { billingState } from '@/client-config/states/billingState';
|
||||
import { captchaProviderState } from '@/client-config/states/captchaProviderState';
|
||||
import { chromeExtensionIdState } from '@/client-config/states/chromeExtensionIdState';
|
||||
import { clientConfigApiStatusState } from '@/client-config/states/clientConfigApiStatusState';
|
||||
import { isAnalyticsEnabledState } from '@/client-config/states/isAnalyticsEnabledState';
|
||||
import { isClientConfigLoadedState } from '@/client-config/states/isClientConfigLoadedState';
|
||||
import { isDebugModeState } from '@/client-config/states/isDebugModeState';
|
||||
import { isSignInPrefilledState } from '@/client-config/states/isSignInPrefilledState';
|
||||
import { isSignUpDisabledState } from '@/client-config/states/isSignUpDisabledState';
|
||||
@ -27,8 +27,8 @@ export const ClientConfigProviderEffect = () => {
|
||||
const setSupportChat = useSetRecoilState(supportChatState);
|
||||
|
||||
const setSentryConfig = useSetRecoilState(sentryConfigState);
|
||||
const [isClientConfigLoaded, setIsClientConfigLoaded] = useRecoilState(
|
||||
isClientConfigLoadedState,
|
||||
const [clientConfigApiStatus, setClientConfigApiStatus] = useRecoilState(
|
||||
clientConfigApiStatusState,
|
||||
);
|
||||
|
||||
const setCaptchaProvider = useSetRecoilState(captchaProviderState);
|
||||
@ -37,42 +37,64 @@ export const ClientConfigProviderEffect = () => {
|
||||
|
||||
const setApiConfig = useSetRecoilState(apiConfigState);
|
||||
|
||||
const { data, loading } = useGetClientConfigQuery({
|
||||
skip: isClientConfigLoaded,
|
||||
const { data, loading, error } = useGetClientConfigQuery({
|
||||
skip: clientConfigApiStatus.isLoaded,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading && isDefined(data?.clientConfig)) {
|
||||
setIsClientConfigLoaded(true);
|
||||
setAuthProviders({
|
||||
google: data?.clientConfig.authProviders.google,
|
||||
microsoft: data?.clientConfig.authProviders.microsoft,
|
||||
password: data?.clientConfig.authProviders.password,
|
||||
magicLink: false,
|
||||
sso: data?.clientConfig.authProviders.sso,
|
||||
});
|
||||
setIsDebugMode(data?.clientConfig.debugMode);
|
||||
setIsAnalyticsEnabled(data?.clientConfig.analyticsEnabled);
|
||||
setIsSignInPrefilled(data?.clientConfig.signInPrefilled);
|
||||
setIsSignUpDisabled(data?.clientConfig.signUpDisabled);
|
||||
if (loading) return;
|
||||
setClientConfigApiStatus((currentStatus) => ({
|
||||
...currentStatus,
|
||||
isLoaded: true,
|
||||
}));
|
||||
|
||||
setBilling(data?.clientConfig.billing);
|
||||
setSupportChat(data?.clientConfig.support);
|
||||
|
||||
setSentryConfig({
|
||||
dsn: data?.clientConfig?.sentry?.dsn,
|
||||
release: data?.clientConfig?.sentry?.release,
|
||||
environment: data?.clientConfig?.sentry?.environment,
|
||||
});
|
||||
|
||||
setCaptchaProvider({
|
||||
provider: data?.clientConfig?.captcha?.provider,
|
||||
siteKey: data?.clientConfig?.captcha?.siteKey,
|
||||
});
|
||||
|
||||
setChromeExtensionId(data?.clientConfig?.chromeExtensionId);
|
||||
setApiConfig(data?.clientConfig?.api);
|
||||
if (error instanceof Error) {
|
||||
setClientConfigApiStatus((currentStatus) => ({
|
||||
...currentStatus,
|
||||
isErrored: true,
|
||||
error,
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isDefined(data?.clientConfig)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setClientConfigApiStatus((currentStatus) => ({
|
||||
...currentStatus,
|
||||
isErrored: false,
|
||||
error: undefined,
|
||||
}));
|
||||
|
||||
setAuthProviders({
|
||||
google: data?.clientConfig.authProviders.google,
|
||||
microsoft: data?.clientConfig.authProviders.microsoft,
|
||||
password: data?.clientConfig.authProviders.password,
|
||||
magicLink: false,
|
||||
sso: data?.clientConfig.authProviders.sso,
|
||||
});
|
||||
setIsDebugMode(data?.clientConfig.debugMode);
|
||||
setIsAnalyticsEnabled(data?.clientConfig.analyticsEnabled);
|
||||
setIsSignInPrefilled(data?.clientConfig.signInPrefilled);
|
||||
setIsSignUpDisabled(data?.clientConfig.signUpDisabled);
|
||||
|
||||
setBilling(data?.clientConfig.billing);
|
||||
setSupportChat(data?.clientConfig.support);
|
||||
|
||||
setSentryConfig({
|
||||
dsn: data?.clientConfig?.sentry?.dsn,
|
||||
release: data?.clientConfig?.sentry?.release,
|
||||
environment: data?.clientConfig?.sentry?.environment,
|
||||
});
|
||||
|
||||
setCaptchaProvider({
|
||||
provider: data?.clientConfig?.captcha?.provider,
|
||||
siteKey: data?.clientConfig?.captcha?.siteKey,
|
||||
});
|
||||
|
||||
setChromeExtensionId(data?.clientConfig?.chromeExtensionId);
|
||||
setApiConfig(data?.clientConfig?.api);
|
||||
}, [
|
||||
data,
|
||||
setAuthProviders,
|
||||
@ -83,11 +105,12 @@ export const ClientConfigProviderEffect = () => {
|
||||
setBilling,
|
||||
setSentryConfig,
|
||||
loading,
|
||||
setIsClientConfigLoaded,
|
||||
setClientConfigApiStatus,
|
||||
setCaptchaProvider,
|
||||
setChromeExtensionId,
|
||||
setApiConfig,
|
||||
setIsAnalyticsEnabled,
|
||||
error,
|
||||
]);
|
||||
|
||||
return <></>;
|
||||
|
||||
Reference in New Issue
Block a user